merge in updates from upstream
This commit is contained in:
parent
ff228d477e
commit
c5bd65ac05
235
ph-init/src/init.rs
Normal file
235
ph-init/src/init.rs
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
|
||||||
|
use crate::{Error,Result};
|
||||||
|
use crate::cmdline::CmdLine;
|
||||||
|
use crate::sys::{sethostname, setsid, set_controlling_tty, mount_devtmpfs, mount_tmpfs, mkdir, umount, mount_sysfs, mount_procfs, mount_devpts, chown, chmod, create_directories, mount_overlay, move_mount, pivot_root, mount_9p, mount, waitpid, reboot, getpid};
|
||||||
|
use std::path::Path;
|
||||||
|
use std::{fs, process, io};
|
||||||
|
use crate::service::{Service, ServiceLaunch};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
pub struct InitServer {
|
||||||
|
hostname: String,
|
||||||
|
cmdline: CmdLine,
|
||||||
|
rootfs: RootFS,
|
||||||
|
services: BTreeMap<u32, Service>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InitServer {
|
||||||
|
pub fn create(hostname: &str) -> Result<InitServer> {
|
||||||
|
Self::check_pid1()?;
|
||||||
|
sethostname(hostname)?;
|
||||||
|
setsid()?;
|
||||||
|
set_controlling_tty(0, true)?;
|
||||||
|
|
||||||
|
let hostname = hostname.to_string();
|
||||||
|
let cmdline = CmdLine::load()?;
|
||||||
|
let rootfs = RootFS::load(&cmdline)?;
|
||||||
|
let services = BTreeMap::new();
|
||||||
|
|
||||||
|
Ok(InitServer {
|
||||||
|
hostname,
|
||||||
|
cmdline,
|
||||||
|
rootfs,
|
||||||
|
services,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_pid1() -> Result<()> {
|
||||||
|
if getpid() == 1 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::Pid1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_filesystem(&self) -> Result<()> {
|
||||||
|
mount_devtmpfs()?;
|
||||||
|
mount_tmpfs("/tmp")?;
|
||||||
|
mkdir("/tmp/sysroot")?;
|
||||||
|
if self.rootfs.read_only() {
|
||||||
|
self.setup_readonly_root()?;
|
||||||
|
} else {
|
||||||
|
self.setup_writeable_root()?;
|
||||||
|
}
|
||||||
|
umount("/opt/ph/tmp")?;
|
||||||
|
umount("/opt/ph/proc")?;
|
||||||
|
umount("/opt/ph/dev")?;
|
||||||
|
|
||||||
|
mount_sysfs()?;
|
||||||
|
mount_procfs()?;
|
||||||
|
mount_devtmpfs()?;
|
||||||
|
mount_devpts()?;
|
||||||
|
mount_tmpfs("/run")?;
|
||||||
|
mkdir("/run/user")?;
|
||||||
|
mkdir("/run/user/1000")?;
|
||||||
|
chown("/run/user/1000", 1000,1000)?;
|
||||||
|
if Path::new("/dev/wl0").exists() {
|
||||||
|
chmod("/dev/wl0", 0o666)?;
|
||||||
|
}
|
||||||
|
self.mount_home_if_exists()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_readonly_root(&self) -> Result<()> {
|
||||||
|
create_directories(&[
|
||||||
|
"/tmp/ro",
|
||||||
|
"/tmp/rw",
|
||||||
|
"/tmp/rw/upper",
|
||||||
|
"/tmp/rw/work",
|
||||||
|
])?;
|
||||||
|
mount_tmpfs("/tmp/rw")?;
|
||||||
|
create_directories(&["/tmp/rw/upper", "/tmp/rw/work"])?;
|
||||||
|
self.rootfs.mount("/tmp/ro")?;
|
||||||
|
mount_overlay("/tmp/sysroot",
|
||||||
|
"lowerdir=/tmp/ro,upperdir=/tmp/rw/upper,workdir=/tmp/rw/work")?;
|
||||||
|
create_directories(&[
|
||||||
|
"/tmp/sysroot/ro",
|
||||||
|
"/tmp/sysroot/rw"
|
||||||
|
])?;
|
||||||
|
move_mount("/tmp/ro", "/tmp/sysroot/ro")?;
|
||||||
|
move_mount("/tmp/rw", "/tmp/sysroot/rw")?;
|
||||||
|
|
||||||
|
let toolsdir = Path::new("/tmp/sysroot/opt/ph");
|
||||||
|
if !toolsdir.exists() {
|
||||||
|
fs::create_dir_all(toolsdir)
|
||||||
|
.map_err(|e| Error::MkDir(String::from("/tmp/sysroot/opt/ph"), e))?;
|
||||||
|
}
|
||||||
|
pivot_root("/tmp/sysroot", "/tmp/sysroot/opt/ph")?;
|
||||||
|
fs::write("/etc/hosts", format!("127.0.0.1 {} localhost", self.hostname))
|
||||||
|
.map_err(Error::WriteEtcHosts)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_writeable_root(&self) -> Result<()> {
|
||||||
|
self.rootfs.mount("/tmp/sysroot")?;
|
||||||
|
|
||||||
|
let toolsdir = Path::new("/tmp/sysroot/opt/ph");
|
||||||
|
if !toolsdir.exists() {
|
||||||
|
fs::create_dir_all(toolsdir)
|
||||||
|
.map_err(|e| Error::MkDir(String::from("/tmp/sysroot/opt/ph"), e))?;
|
||||||
|
}
|
||||||
|
pivot_root("/tmp/sysroot", "/tmp/sysroot/opt/ph")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_9p_home(&self) -> bool {
|
||||||
|
// XXX
|
||||||
|
// /sys/bus/virtio/drivers/9pnet_virtio/virtio*/mount_tag
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mount_home_if_exists(&self) -> Result<()> {
|
||||||
|
if self.has_9p_home() {
|
||||||
|
let homedir = Path::new("/home/user");
|
||||||
|
if !homedir.exists() {
|
||||||
|
mkdir(homedir)?;
|
||||||
|
}
|
||||||
|
mount_9p("home", "/home/user")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_daemons(&mut self) -> Result<()> {
|
||||||
|
let dbus = ServiceLaunch::new("dbus-daemon", "/usr/bin/dbus-daemon")
|
||||||
|
.base_environment()
|
||||||
|
.uidgid(1000,1000)
|
||||||
|
.arg("--session")
|
||||||
|
.arg("--nosyslog")
|
||||||
|
.arg("--address=unix:path=/run/user/1000/bus")
|
||||||
|
.launch()?;
|
||||||
|
|
||||||
|
self.services.insert(dbus.pid(), dbus);
|
||||||
|
|
||||||
|
let sommelier = ServiceLaunch::new("sommelier", "/opt/ph/usr/bin/sommelier")
|
||||||
|
.base_environment()
|
||||||
|
.uidgid(1000,1000)
|
||||||
|
.arg("--master")
|
||||||
|
.launch()?;
|
||||||
|
|
||||||
|
self.services.insert(sommelier.pid(), sommelier);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn launch_console_shell(&mut self, splash: &'static str) -> Result<()> {
|
||||||
|
let root = self.cmdline.has_var("phinit.rootshell");
|
||||||
|
let realm = self.cmdline.lookup("phinit.realm");
|
||||||
|
|
||||||
|
let shell = ServiceLaunch::new_shell(root, realm)
|
||||||
|
.launch_with_preexec(move || {
|
||||||
|
println!("{}", splash);
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.services.insert(shell.pid(), shell);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) -> Result<()> {
|
||||||
|
loop {
|
||||||
|
if let Some(child) = self.wait_for_child() {
|
||||||
|
println!("Service exited: {}", child.name());
|
||||||
|
if child.name() == "shell" {
|
||||||
|
reboot(libc::RB_AUTOBOOT)
|
||||||
|
.map_err(Error::RebootFailed)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Unknown process exited.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_waitpid_err(err: io::Error) -> ! {
|
||||||
|
if let Some(errno) = err.raw_os_error() {
|
||||||
|
if errno == libc::ECHILD {
|
||||||
|
if let Err(err) = reboot(libc::RB_AUTOBOOT) {
|
||||||
|
println!("reboot() failed: {:?}", err);
|
||||||
|
process::exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("error on waitpid: {:?}", err);
|
||||||
|
process::exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_for_child(&mut self) -> Option<Service> {
|
||||||
|
match waitpid(-1, 0) {
|
||||||
|
Ok((pid,_status)) => self.services.remove(&(pid as u32)),
|
||||||
|
Err(err) => Self::handle_waitpid_err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct RootFS {
|
||||||
|
root: String,
|
||||||
|
fstype: String,
|
||||||
|
rootflags: Option<String>,
|
||||||
|
readonly: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RootFS {
|
||||||
|
fn load(cmdline: &CmdLine) -> Result<Self> {
|
||||||
|
let root = cmdline.lookup("phinit.root")
|
||||||
|
.ok_or(Error::NoRootVar)?;
|
||||||
|
let fstype = cmdline.lookup("phinit.rootfstype")
|
||||||
|
.ok_or(Error::NoRootFsVar)?;
|
||||||
|
let rootflags = cmdline.lookup("phinit.rootflags");
|
||||||
|
let readonly = !cmdline.has_var("phinit.root_rw");
|
||||||
|
|
||||||
|
Ok(RootFS {
|
||||||
|
root, fstype, rootflags, readonly
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_only(&self) -> bool {
|
||||||
|
self.readonly
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mount(&self, target: &str) -> Result<()> {
|
||||||
|
let options = self.rootflags.as_ref().map(|s| s.as_str());
|
||||||
|
let flags = libc::MS_RDONLY;
|
||||||
|
|
||||||
|
mount(&self.root, target, &self.fstype, flags, options)
|
||||||
|
.map_err(|e| Error::RootFsMount(self.root.clone(), e))
|
||||||
|
}
|
||||||
|
}
|
58
ph-init/src/service.rs
Normal file
58
ph-init/src/service.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
|
const DEFAULT_ENVIRONMENT: &[&str] = &[
|
||||||
|
"SHELL=/bin/bash",
|
||||||
|
"TERM=xterm-256-color",
|
||||||
|
"LANG=en_US.UTF8",
|
||||||
|
"LC_COLLATE=C",
|
||||||
|
"GNOME_DESKTOP_SESSION_ID=this-is-deprecated",
|
||||||
|
"XDR_RUNTIME_DIR=/run/user/1000",
|
||||||
|
"NO_AT_BRIDGE=1",
|
||||||
|
"DISPLAY=:0",
|
||||||
|
"XDG_SESSION_TYPE=wayland",
|
||||||
|
"GDK_BACKEND=wayland",
|
||||||
|
"WAYLAND_DISPLAY=wayland-0",
|
||||||
|
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus",
|
||||||
|
];
|
||||||
|
|
||||||
|
pub struct Launcher {
|
||||||
|
command: Command,
|
||||||
|
uidgid: Option((u32,u32)),
|
||||||
|
environment: Vec<String>,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Launcher {
|
||||||
|
|
||||||
|
pub fn new(cmd: &str) -> Self {
|
||||||
|
let command = Command::new(cmd);
|
||||||
|
let uidgid = None;
|
||||||
|
let environment = Vec::new();
|
||||||
|
|
||||||
|
Launcher { command, uidgid, environment }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_shell(root: bool) -> Self {
|
||||||
|
let mut launcher = Self::new("/bin/bash");
|
||||||
|
|
||||||
|
if root {
|
||||||
|
launcher.env("HOME", "/");
|
||||||
|
} else {
|
||||||
|
launcher.env("HOME", "/home/user");
|
||||||
|
launcher.uidgid = Some((1000,1000));
|
||||||
|
}
|
||||||
|
launcher
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn env<K,V>(&mut self, name: K, val: V)
|
||||||
|
where K: AsRef<OsStr>, V: AsRef<OsStr>
|
||||||
|
{
|
||||||
|
self.command.env(name, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) {
|
||||||
|
self.command.arg(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -13,12 +13,12 @@ group("all") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!defined(peer_cmd_prefix)) {
|
if (!defined(peer_cmd_prefix)) {
|
||||||
# if (use.amd64) {
|
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 \\\"\\\"\""
|
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) {
|
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 \\\"\\\"\""
|
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.
|
# Set this to the Xwayland path.
|
||||||
@ -64,6 +64,7 @@ wayland_protocol_library("sommelier-protocol") {
|
|||||||
"protocol/gtk-shell.xml",
|
"protocol/gtk-shell.xml",
|
||||||
"protocol/keyboard-extension-unstable-v1.xml",
|
"protocol/keyboard-extension-unstable-v1.xml",
|
||||||
"protocol/linux-dmabuf-unstable-v1.xml",
|
"protocol/linux-dmabuf-unstable-v1.xml",
|
||||||
|
"protocol/pointer-constraints-unstable-v1.xml",
|
||||||
"protocol/relative-pointer-unstable-v1.xml",
|
"protocol/relative-pointer-unstable-v1.xml",
|
||||||
"protocol/text-input-unstable-v1.xml",
|
"protocol/text-input-unstable-v1.xml",
|
||||||
"protocol/viewporter.xml",
|
"protocol/viewporter.xml",
|
||||||
@ -97,6 +98,7 @@ executable("sommelier") {
|
|||||||
"sommelier-drm.c",
|
"sommelier-drm.c",
|
||||||
"sommelier-gtk-shell.c",
|
"sommelier-gtk-shell.c",
|
||||||
"sommelier-output.c",
|
"sommelier-output.c",
|
||||||
|
"sommelier-pointer-constraints.c",
|
||||||
"sommelier-relative-pointer-manager.c",
|
"sommelier-relative-pointer-manager.c",
|
||||||
"sommelier-seat.c",
|
"sommelier-seat.c",
|
||||||
"sommelier-shell.c",
|
"sommelier-shell.c",
|
||||||
|
@ -6,7 +6,7 @@ PREFIX = /usr
|
|||||||
SYSCONFDIR = /etc
|
SYSCONFDIR = /etc
|
||||||
BINDIR = $(PREFIX)/bin
|
BINDIR = $(PREFIX)/bin
|
||||||
SRCFILES := sommelier.c version.h
|
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
|
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 protocol/pointer-constraints-unstable-v1.xml
|
||||||
AUXFILES := Makefile README LICENSE AUTHORS sommelier@.service.in sommelier-x@.service.in sommelierrc sommelier.sh
|
AUXFILES := Makefile README LICENSE AUTHORS sommelier@.service.in sommelier-x@.service.in sommelierrc sommelier.sh
|
||||||
ALLFILES := $(SRCFILES) $(XMLFILES) $(AUXFILES)
|
ALLFILES := $(SRCFILES) $(XMLFILES) $(AUXFILES)
|
||||||
#GIT_VERSION := $(shell git describe --abbrev=4 --dirty --always --tags)
|
#GIT_VERSION := $(shell git describe --abbrev=4 --dirty --always --tags)
|
||||||
@ -17,8 +17,8 @@ DIST_VERSION_MINOR := $(word 2,$(DIST_VERSION_BITS))
|
|||||||
DIST_VERSION_MINOR_NEXT := $(shell expr $(DIST_VERSION_MINOR) + 1)
|
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\"
|
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`
|
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
|
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 pointer-constraints-unstable-v1-client-protocol.h pointer-constraints-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
|
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 sommelier-pointer-constraints.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 pointer-constraints-unstable-v1-protocol.o
|
||||||
|
|
||||||
#all: sommelier sommelier@.service sommelier-x@.service
|
#all: sommelier sommelier@.service sommelier-x@.service
|
||||||
all: sommelier
|
all: sommelier
|
||||||
|
339
sommelier/protocol/pointer-constraints-unstable-v1.xml
Normal file
339
sommelier/protocol/pointer-constraints-unstable-v1.xml
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="pointer_constraints_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 constraining pointer motions">
|
||||||
|
This protocol specifies a set of interfaces used for adding constraints to
|
||||||
|
the motion of a pointer. Possible constraints include confining pointer
|
||||||
|
motions to a given region, or locking it to its current position.
|
||||||
|
|
||||||
|
In order to constrain the pointer, a client must first bind the global
|
||||||
|
interface "wp_pointer_constraints" which, if a compositor supports pointer
|
||||||
|
constraints, is exposed by the registry. Using the bound global object, the
|
||||||
|
client uses the request that corresponds to the type of constraint it wants
|
||||||
|
to make. See wp_pointer_constraints 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_pointer_constraints_v1" version="1">
|
||||||
|
<description summary="constrain the movement of a pointer">
|
||||||
|
The global interface exposing pointer constraining functionality. It
|
||||||
|
exposes two requests: lock_pointer for locking the pointer to its
|
||||||
|
position, and confine_pointer for locking the pointer to a region.
|
||||||
|
|
||||||
|
The lock_pointer and confine_pointer requests create the objects
|
||||||
|
wp_locked_pointer and wp_confined_pointer respectively, and the client can
|
||||||
|
use these objects to interact with the lock.
|
||||||
|
|
||||||
|
For any surface, only one lock or confinement may be active across all
|
||||||
|
wl_pointer objects of the same seat. If a lock or confinement is requested
|
||||||
|
when another lock or confinement is active or requested on the same surface
|
||||||
|
and with any of the wl_pointer objects of the same seat, an
|
||||||
|
'already_constrained' error will be raised.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<description summary="wp_pointer_constraints error values">
|
||||||
|
These errors can be emitted in response to wp_pointer_constraints
|
||||||
|
requests.
|
||||||
|
</description>
|
||||||
|
<entry name="already_constrained" value="1"
|
||||||
|
summary="pointer constraint already requested on that surface"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<enum name="lifetime">
|
||||||
|
<description summary="constraint lifetime">
|
||||||
|
These values represent different lifetime semantics. They are passed
|
||||||
|
as arguments to the factory requests to specify how the constraint
|
||||||
|
lifetimes should be managed.
|
||||||
|
</description>
|
||||||
|
<entry name="oneshot" value="1">
|
||||||
|
<description summary="the pointer constraint is defunct once deactivated">
|
||||||
|
A oneshot pointer constraint will never reactivate once it has been
|
||||||
|
deactivated. See the corresponding deactivation event
|
||||||
|
(wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for
|
||||||
|
details.
|
||||||
|
</description>
|
||||||
|
</entry>
|
||||||
|
<entry name="persistent" value="2">
|
||||||
|
<description summary="the pointer constraint may reactivate">
|
||||||
|
A persistent pointer constraint may again reactivate once it has
|
||||||
|
been deactivated. See the corresponding deactivation event
|
||||||
|
(wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for
|
||||||
|
details.
|
||||||
|
</description>
|
||||||
|
</entry>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the pointer constraints manager object">
|
||||||
|
Used by the client to notify the server that it will no longer use this
|
||||||
|
pointer constraints object.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="lock_pointer">
|
||||||
|
<description summary="lock pointer to a position">
|
||||||
|
The lock_pointer request lets the client request to disable movements of
|
||||||
|
the virtual pointer (i.e. the cursor), effectively locking the pointer
|
||||||
|
to a position. This request may not take effect immediately; in the
|
||||||
|
future, when the compositor deems implementation-specific constraints
|
||||||
|
are satisfied, the pointer lock will be activated and the compositor
|
||||||
|
sends a locked event.
|
||||||
|
|
||||||
|
The protocol provides no guarantee that the constraints are ever
|
||||||
|
satisfied, and does not require the compositor to send an error if the
|
||||||
|
constraints cannot ever be satisfied. It is thus possible to request a
|
||||||
|
lock that will never activate.
|
||||||
|
|
||||||
|
There may not be another pointer constraint of any kind requested or
|
||||||
|
active on the surface for any of the wl_pointer objects of the seat of
|
||||||
|
the passed pointer when requesting a lock. If there is, an error will be
|
||||||
|
raised. See general pointer lock documentation for more details.
|
||||||
|
|
||||||
|
The intersection of the region passed with this request and the input
|
||||||
|
region of the surface is used to determine where the pointer must be
|
||||||
|
in order for the lock to activate. It is up to the compositor whether to
|
||||||
|
warp the pointer or require some kind of user interaction for the lock
|
||||||
|
to activate. If the region is null the surface input region is used.
|
||||||
|
|
||||||
|
A surface may receive pointer focus without the lock being activated.
|
||||||
|
|
||||||
|
The request creates a new object wp_locked_pointer which is used to
|
||||||
|
interact with the lock as well as receive updates about its state. See
|
||||||
|
the the description of wp_locked_pointer for further information.
|
||||||
|
|
||||||
|
Note that while a pointer is locked, the wl_pointer objects of the
|
||||||
|
corresponding seat will not emit any wl_pointer.motion events, but
|
||||||
|
relative motion events will still be emitted via wp_relative_pointer
|
||||||
|
objects of the same seat. wl_pointer.axis and wl_pointer.button events
|
||||||
|
are unaffected.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_locked_pointer_v1"/>
|
||||||
|
<arg name="surface" type="object" interface="wl_surface"
|
||||||
|
summary="surface to lock pointer to"/>
|
||||||
|
<arg name="pointer" type="object" interface="wl_pointer"
|
||||||
|
summary="the pointer that should be locked"/>
|
||||||
|
<arg name="region" type="object" interface="wl_region" allow-null="true"
|
||||||
|
summary="region of surface"/>
|
||||||
|
<arg name="lifetime" type="uint" summary="lock lifetime"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="confine_pointer">
|
||||||
|
<description summary="confine pointer to a region">
|
||||||
|
The confine_pointer request lets the client request to confine the
|
||||||
|
pointer cursor to a given region. This request may not take effect
|
||||||
|
immediately; in the future, when the compositor deems implementation-
|
||||||
|
specific constraints are satisfied, the pointer confinement will be
|
||||||
|
activated and the compositor sends a confined event.
|
||||||
|
|
||||||
|
The intersection of the region passed with this request and the input
|
||||||
|
region of the surface is used to determine where the pointer must be
|
||||||
|
in order for the confinement to activate. It is up to the compositor
|
||||||
|
whether to warp the pointer or require some kind of user interaction for
|
||||||
|
the confinement to activate. If the region is null the surface input
|
||||||
|
region is used.
|
||||||
|
|
||||||
|
The request will create a new object wp_confined_pointer which is used
|
||||||
|
to interact with the confinement as well as receive updates about its
|
||||||
|
state. See the the description of wp_confined_pointer for further
|
||||||
|
information.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_confined_pointer_v1"/>
|
||||||
|
<arg name="surface" type="object" interface="wl_surface"
|
||||||
|
summary="surface to lock pointer to"/>
|
||||||
|
<arg name="pointer" type="object" interface="wl_pointer"
|
||||||
|
summary="the pointer that should be confined"/>
|
||||||
|
<arg name="region" type="object" interface="wl_region" allow-null="true"
|
||||||
|
summary="region of surface"/>
|
||||||
|
<arg name="lifetime" type="uint" summary="confinement lifetime"/>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_locked_pointer_v1" version="1">
|
||||||
|
<description summary="receive relative pointer motion events">
|
||||||
|
The wp_locked_pointer interface represents a locked pointer state.
|
||||||
|
|
||||||
|
While the lock of this object is active, the wl_pointer objects of the
|
||||||
|
associated seat will not emit any wl_pointer.motion events.
|
||||||
|
|
||||||
|
This object will send the event 'locked' when the lock is activated.
|
||||||
|
Whenever the lock is activated, it is guaranteed that the locked surface
|
||||||
|
will already have received pointer focus and that the pointer will be
|
||||||
|
within the region passed to the request creating this object.
|
||||||
|
|
||||||
|
To unlock the pointer, send the destroy request. This will also destroy
|
||||||
|
the wp_locked_pointer object.
|
||||||
|
|
||||||
|
If the compositor decides to unlock the pointer the unlocked event is
|
||||||
|
sent. See wp_locked_pointer.unlock for details.
|
||||||
|
|
||||||
|
When unlocking, the compositor may warp the cursor position to the set
|
||||||
|
cursor position hint. If it does, it will not result in any relative
|
||||||
|
motion events emitted via wp_relative_pointer.
|
||||||
|
|
||||||
|
If the surface the lock was requested on is destroyed and the lock is not
|
||||||
|
yet activated, the wp_locked_pointer object is now defunct and must be
|
||||||
|
destroyed.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the locked pointer object">
|
||||||
|
Destroy the locked pointer object. If applicable, the compositor will
|
||||||
|
unlock the pointer.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_cursor_position_hint">
|
||||||
|
<description summary="set the pointer cursor position hint">
|
||||||
|
Set the cursor position hint relative to the top left corner of the
|
||||||
|
surface.
|
||||||
|
|
||||||
|
If the client is drawing its own cursor, it should update the position
|
||||||
|
hint to the position of its own cursor. A compositor may use this
|
||||||
|
information to warp the pointer upon unlock in order to avoid pointer
|
||||||
|
jumps.
|
||||||
|
|
||||||
|
The cursor position hint is double buffered. The new hint will only take
|
||||||
|
effect when the associated surface gets it pending state applied. See
|
||||||
|
wl_surface.commit for details.
|
||||||
|
</description>
|
||||||
|
<arg name="surface_x" type="fixed"
|
||||||
|
summary="surface-local x coordinate"/>
|
||||||
|
<arg name="surface_y" type="fixed"
|
||||||
|
summary="surface-local y coordinate"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_region">
|
||||||
|
<description summary="set a new lock region">
|
||||||
|
Set a new region used to lock the pointer.
|
||||||
|
|
||||||
|
The new lock region is double-buffered. The new lock region will
|
||||||
|
only take effect when the associated surface gets its pending state
|
||||||
|
applied. See wl_surface.commit for details.
|
||||||
|
|
||||||
|
For details about the lock region, see wp_locked_pointer.
|
||||||
|
</description>
|
||||||
|
<arg name="region" type="object" interface="wl_region" allow-null="true"
|
||||||
|
summary="region of surface"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="locked">
|
||||||
|
<description summary="lock activation event">
|
||||||
|
Notification that the pointer lock of the seat's pointer is activated.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="unlocked">
|
||||||
|
<description summary="lock deactivation event">
|
||||||
|
Notification that the pointer lock of the seat's pointer is no longer
|
||||||
|
active. If this is a oneshot pointer lock (see
|
||||||
|
wp_pointer_constraints.lifetime) this object is now defunct and should
|
||||||
|
be destroyed. If this is a persistent pointer lock (see
|
||||||
|
wp_pointer_constraints.lifetime) this pointer lock may again
|
||||||
|
reactivate in the future.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_confined_pointer_v1" version="1">
|
||||||
|
<description summary="confined pointer object">
|
||||||
|
The wp_confined_pointer interface represents a confined pointer state.
|
||||||
|
|
||||||
|
This object will send the event 'confined' when the confinement is
|
||||||
|
activated. Whenever the confinement is activated, it is guaranteed that
|
||||||
|
the surface the pointer is confined to will already have received pointer
|
||||||
|
focus and that the pointer will be within the region passed to the request
|
||||||
|
creating this object. It is up to the compositor to decide whether this
|
||||||
|
requires some user interaction and if the pointer will warp to within the
|
||||||
|
passed region if outside.
|
||||||
|
|
||||||
|
To unconfine the pointer, send the destroy request. This will also destroy
|
||||||
|
the wp_confined_pointer object.
|
||||||
|
|
||||||
|
If the compositor decides to unconfine the pointer the unconfined event is
|
||||||
|
sent. The wp_confined_pointer object is at this point defunct and should
|
||||||
|
be destroyed.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the confined pointer object">
|
||||||
|
Destroy the confined pointer object. If applicable, the compositor will
|
||||||
|
unconfine the pointer.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_region">
|
||||||
|
<description summary="set a new confine region">
|
||||||
|
Set a new region used to confine the pointer.
|
||||||
|
|
||||||
|
The new confine region is double-buffered. The new confine region will
|
||||||
|
only take effect when the associated surface gets its pending state
|
||||||
|
applied. See wl_surface.commit for details.
|
||||||
|
|
||||||
|
If the confinement is active when the new confinement region is applied
|
||||||
|
and the pointer ends up outside of newly applied region, the pointer may
|
||||||
|
warped to a position within the new confinement region. If warped, a
|
||||||
|
wl_pointer.motion event will be emitted, but no
|
||||||
|
wp_relative_pointer.relative_motion event.
|
||||||
|
|
||||||
|
The compositor may also, instead of using the new region, unconfine the
|
||||||
|
pointer.
|
||||||
|
|
||||||
|
For details about the confine region, see wp_confined_pointer.
|
||||||
|
</description>
|
||||||
|
<arg name="region" type="object" interface="wl_region" allow-null="true"
|
||||||
|
summary="region of surface"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="confined">
|
||||||
|
<description summary="pointer confined">
|
||||||
|
Notification that the pointer confinement of the seat's pointer is
|
||||||
|
activated.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="unconfined">
|
||||||
|
<description summary="pointer unconfined">
|
||||||
|
Notification that the pointer confinement of the seat's pointer is no
|
||||||
|
longer active. If this is a oneshot pointer confinement (see
|
||||||
|
wp_pointer_constraints.lifetime) this object is now defunct and should
|
||||||
|
be destroyed. If this is a persistent pointer confinement (see
|
||||||
|
wp_pointer_constraints.lifetime) this pointer confinement may again
|
||||||
|
reactivate in the future.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
</protocol>
|
@ -33,12 +33,6 @@
|
|||||||
#define DMA_BUF_BASE 'b'
|
#define DMA_BUF_BASE 'b'
|
||||||
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
|
#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_host_compositor {
|
||||||
struct sl_compositor* compositor;
|
struct sl_compositor* compositor;
|
||||||
struct wl_resource* resource;
|
struct wl_resource* resource;
|
||||||
|
@ -58,8 +58,7 @@ static void sl_drm_create_planar_buffer(struct wl_client* client,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void sl_drm_sync(struct sl_context* ctx,
|
static void sl_drm_sync(struct sl_context* ctx,
|
||||||
struct sl_sync_point* sync_point)
|
struct sl_sync_point* sync_point) {
|
||||||
{
|
|
||||||
int drm_fd = gbm_device_get_fd(ctx->gbm);
|
int drm_fd = gbm_device_get_fd(ctx->gbm);
|
||||||
struct drm_prime_handle prime_handle;
|
struct drm_prime_handle prime_handle;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -15,13 +15,10 @@
|
|||||||
|
|
||||||
#define INCH_IN_MM 25.4
|
#define INCH_IN_MM 25.4
|
||||||
|
|
||||||
// The ergonomic advice for monitor distance is 50-75cm away, with laptops
|
// Legacy X11 applications use DPI to decide on their scale. This value is what
|
||||||
// expected to be closer. This magic number is designed to correct that for the
|
// the convention for a "normal" scale is. One way to verify the convention is
|
||||||
// purpose of calculating a "useful" DPI.
|
// to note the DPI of a typical monitor circa ~2005, i.e. 20" 1080p.
|
||||||
//
|
#define DEFACTO_DPI 96
|
||||||
// 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) {
|
double sl_output_aura_scale_factor_to_double(int scale_factor) {
|
||||||
// Aura scale factor is an enum that for all currently know values
|
// Aura scale factor is an enum that for all currently know values
|
||||||
@ -30,88 +27,105 @@ double sl_output_aura_scale_factor_to_double(int scale_factor) {
|
|||||||
return scale_factor / 1000.0;
|
return scale_factor / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dpi_to_physical_mm(double dpi, int px) {
|
||||||
|
return px * (INCH_IN_MM / dpi);
|
||||||
|
}
|
||||||
|
|
||||||
void sl_output_get_host_output_state(struct sl_host_output* host,
|
void sl_output_get_host_output_state(struct sl_host_output* host,
|
||||||
int* scale,
|
int* scale,
|
||||||
int* physical_width,
|
int* physical_width,
|
||||||
int* physical_height,
|
int* physical_height,
|
||||||
int* width,
|
int* width,
|
||||||
int* height) {
|
int* height) {
|
||||||
double preferred_scale =
|
// The user's chosen zoom level.
|
||||||
sl_output_aura_scale_factor_to_double(host->preferred_scale);
|
|
||||||
double current_scale =
|
double current_scale =
|
||||||
sl_output_aura_scale_factor_to_double(host->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.
|
// The scale applied to a screen at the default zoom. I.e. this value
|
||||||
if (host->ctx->aura_shell) {
|
// determines the meaning of "100%" zoom, and how zoom relates to the
|
||||||
|
// apparent resolution:
|
||||||
|
//
|
||||||
|
// apparent_res = native_res / device_scale_factor * current_scale
|
||||||
|
//
|
||||||
|
// e.g.: On a device with a DSF of 2.0, 80% zoom really means "apply 1.6x
|
||||||
|
// scale", and 50% zoom would give you an apparent resolution equal to the
|
||||||
|
// native one.
|
||||||
double device_scale_factor =
|
double device_scale_factor =
|
||||||
sl_output_aura_scale_factor_to_double(host->device_scale_factor);
|
sl_output_aura_scale_factor_to_double(host->device_scale_factor);
|
||||||
|
|
||||||
ideal_scale_factor = device_scale_factor * preferred_scale;
|
// Optimistically, we will try to apply the scale that the user chose.
|
||||||
scale_factor = device_scale_factor * current_scale;
|
// Failing that, we will use the scale set for this wl_output.
|
||||||
|
double applied_scale = device_scale_factor * current_scale;
|
||||||
|
if (!host->ctx->aura_shell) {
|
||||||
|
applied_scale = host->scale_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always use scale=1 and adjust geometry and mode based on ideal
|
int target_dpi = DEFACTO_DPI;
|
||||||
// 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 (host->ctx->xwayland) {
|
||||||
|
// For X11, we must fix the scale to be 1 (since X apps typically can't
|
||||||
|
// handle scaling). As a result, we adjust the resolution (based on the
|
||||||
|
// scale we want to apply and sommelier's configuration) and the physical
|
||||||
|
// dimensions (based on what DPI we want the applications to use). E.g.:
|
||||||
|
// - Device scale is 1.25x, with 1920x1080 resolution on a 295mm by 165mm
|
||||||
|
// screen.
|
||||||
|
// - User chosen zoom is 130%
|
||||||
|
// - Sommelier is scaled to 0.5 (a.k.a low density). Since ctx->scale also
|
||||||
|
// has the device scale, it will be 0.625 (i.e. 0.5 * 1.25).
|
||||||
|
// - We want the DPI to be 120 (i.e. 96 * 1.25)
|
||||||
|
// - Meaning 0.21 mm/px
|
||||||
|
// - We report resolution 738x415 (1920x1080 * 0.5 / 1.3)
|
||||||
|
// - We report dimensions 155mm by 87mm (738x415 * 0.21)
|
||||||
|
// This is mostly expected, another way of thinking about them is that zoom
|
||||||
|
// and scale modify the application's understanding of length:
|
||||||
|
// - Increasing the zoom makes lengths appear longer (i.e. fewer mm to work
|
||||||
|
// with over the same real length).
|
||||||
|
// - Scaling the screen does the inverse.
|
||||||
if (scale)
|
if (scale)
|
||||||
*scale = 1;
|
*scale = 1;
|
||||||
*physical_width = host->physical_width * ideal_scale_factor / scale_factor;
|
*width = host->width * host->ctx->scale / applied_scale;
|
||||||
*physical_height =
|
*height = host->height * host->ctx->scale / applied_scale;
|
||||||
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
|
target_dpi = DEFACTO_DPI * device_scale_factor;
|
||||||
// ideal). The main problem is that in order to facilitate this, many X
|
*physical_width = dpi_to_physical_mm(target_dpi, *width);
|
||||||
// utilities lie about the DPI of the device in order to achieve the desired
|
*physical_height = dpi_to_physical_mm(target_dpi, *height);
|
||||||
// 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 {
|
} else {
|
||||||
int s = MIN(ceil(scale_factor / host->ctx->scale), MAX_OUTPUT_SCALE);
|
// For wayland, we directly apply the scale which combines the user's chosen
|
||||||
|
// preference (from aura) and the scale which this sommelier was configured
|
||||||
|
// for (i.e. based on ctx->scale, which comes from the env/cmd line).
|
||||||
|
//
|
||||||
|
// See above comment: ctx->scale already has the device_scale_factor in it,
|
||||||
|
// so this maths actually looks like:
|
||||||
|
//
|
||||||
|
// applied / ctx->scale
|
||||||
|
// = (current*DSF) / (config*DSF)
|
||||||
|
// = current / config
|
||||||
|
//
|
||||||
|
// E.g. if we configured sommelier to scale everything 0.5x, and the user
|
||||||
|
// has chosen 130% zoom, we are applying 2.6x scale factor.
|
||||||
|
int s = MIN(ceil(applied_scale / host->ctx->scale), MAX_OUTPUT_SCALE);
|
||||||
|
|
||||||
if (scale)
|
if (scale)
|
||||||
*scale = s;
|
*scale = s;
|
||||||
*physical_width = host->physical_width;
|
*physical_width = host->physical_width;
|
||||||
*physical_height = host->physical_height;
|
*physical_height = host->physical_height;
|
||||||
*width = host->width * host->ctx->scale * s / scale_factor;
|
*width = host->width * host->ctx->scale * s / applied_scale;
|
||||||
*height = host->height * host->ctx->scale * s / scale_factor;
|
*height = host->height * host->ctx->scale * s / applied_scale;
|
||||||
|
target_dpi = (*width * INCH_IN_MM) / *physical_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host->ctx->dpi.size) {
|
if (host->ctx->dpi.size) {
|
||||||
int dpi = (*width * INCH_IN_MM) / *physical_width;
|
|
||||||
int adjusted_dpi = *((int*)host->ctx->dpi.data);
|
int adjusted_dpi = *((int*)host->ctx->dpi.data);
|
||||||
double mmpd;
|
|
||||||
int* p;
|
int* p;
|
||||||
|
|
||||||
// Choose the DPI bucket which is closest to the apparent DPI which we
|
// Choose the DPI bucket which is closest to the target DPI which we
|
||||||
// calculated above.
|
// calculated above.
|
||||||
wl_array_for_each(p, &host->ctx->dpi) {
|
wl_array_for_each(p, &host->ctx->dpi) {
|
||||||
if (abs(*p - dpi) < abs(adjusted_dpi - dpi))
|
if (abs(*p - target_dpi) < abs(adjusted_dpi - target_dpi))
|
||||||
adjusted_dpi = *p;
|
adjusted_dpi = *p;
|
||||||
}
|
}
|
||||||
|
|
||||||
mmpd = INCH_IN_MM / adjusted_dpi;
|
*physical_width = dpi_to_physical_mm(adjusted_dpi, *width);
|
||||||
*physical_width = *width * mmpd + 0.5;
|
*physical_height = dpi_to_physical_mm(adjusted_dpi, *height);
|
||||||
*physical_height = *height * mmpd + 0.5;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,49 +245,6 @@ static void sl_aura_output_scale(void* data,
|
|||||||
uint32_t scale) {
|
uint32_t scale) {
|
||||||
struct sl_host_output* host = zaura_output_get_user_data(output);
|
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)
|
if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT)
|
||||||
host->current_scale = scale;
|
host->current_scale = scale;
|
||||||
if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED)
|
if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED)
|
||||||
|
230
sommelier/sommelier-pointer-constraints.c
Normal file
230
sommelier/sommelier-pointer-constraints.c
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
// 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-protocol.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
|
||||||
|
#include "pointer-constraints-unstable-v1-server-protocol.h"
|
||||||
|
#include "pointer-constraints-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
|
#define SL_HOST_OBJECT(NAME, INTERFACE) \
|
||||||
|
struct sl_host_##NAME { \
|
||||||
|
struct sl_context* ctx; \
|
||||||
|
struct wl_resource* resource; \
|
||||||
|
struct INTERFACE* proxy; \
|
||||||
|
}; \
|
||||||
|
static void sl_destroy_host_##NAME(struct wl_resource* resource) { \
|
||||||
|
struct sl_host_##NAME* host = wl_resource_get_user_data(resource); \
|
||||||
|
INTERFACE##_destroy(host->proxy); \
|
||||||
|
wl_resource_set_user_data(resource, NULL); \
|
||||||
|
free(host); \
|
||||||
|
} \
|
||||||
|
static void sl_##NAME##_destroy(struct wl_client* client, \
|
||||||
|
struct wl_resource* resource) { \
|
||||||
|
wl_resource_destroy(resource); \
|
||||||
|
}
|
||||||
|
|
||||||
|
SL_HOST_OBJECT(pointer_constraints, zwp_pointer_constraints_v1);
|
||||||
|
|
||||||
|
SL_HOST_OBJECT(locked_pointer, zwp_locked_pointer_v1);
|
||||||
|
|
||||||
|
SL_HOST_OBJECT(confined_pointer, zwp_confined_pointer_v1);
|
||||||
|
|
||||||
|
static void sl_locked_pointer_locked(
|
||||||
|
void* data, struct zwp_locked_pointer_v1* locked_pointer) {
|
||||||
|
struct sl_host_locked_pointer* host =
|
||||||
|
zwp_locked_pointer_v1_get_user_data(locked_pointer);
|
||||||
|
|
||||||
|
zwp_locked_pointer_v1_send_locked(host->resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sl_locked_pointer_unlocked(
|
||||||
|
void* data, struct zwp_locked_pointer_v1* locked_pointer) {
|
||||||
|
struct sl_host_locked_pointer* host =
|
||||||
|
zwp_locked_pointer_v1_get_user_data(locked_pointer);
|
||||||
|
|
||||||
|
zwp_locked_pointer_v1_send_unlocked(host->resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sl_locked_pointer_set_cursor_position_hint(
|
||||||
|
struct wl_client* client,
|
||||||
|
struct wl_resource* resource,
|
||||||
|
wl_fixed_t surface_x,
|
||||||
|
wl_fixed_t surface_y) {
|
||||||
|
struct sl_host_locked_pointer* host = wl_resource_get_user_data(resource);
|
||||||
|
|
||||||
|
zwp_locked_pointer_v1_set_cursor_position_hint(host->proxy, surface_x,
|
||||||
|
surface_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sl_locked_pointer_set_region(struct wl_client* client,
|
||||||
|
struct wl_resource* resource,
|
||||||
|
struct wl_resource* region) {
|
||||||
|
struct sl_host_locked_pointer* host = wl_resource_get_user_data(resource);
|
||||||
|
struct sl_host_region* host_region =
|
||||||
|
region ? wl_resource_get_user_data(region) : NULL;
|
||||||
|
|
||||||
|
zwp_locked_pointer_v1_set_region(host->proxy,
|
||||||
|
host_region ? host_region->proxy : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct zwp_locked_pointer_v1_listener sl_locked_pointer_listener = {
|
||||||
|
sl_locked_pointer_locked,
|
||||||
|
sl_locked_pointer_unlocked,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct zwp_locked_pointer_v1_interface sl_locked_pointer_implementation =
|
||||||
|
{sl_locked_pointer_destroy, sl_locked_pointer_set_cursor_position_hint,
|
||||||
|
sl_locked_pointer_set_region};
|
||||||
|
|
||||||
|
static void sl_confined_pointer_confined(
|
||||||
|
void* data, struct zwp_confined_pointer_v1* confined_pointer) {
|
||||||
|
struct sl_host_confined_pointer* host =
|
||||||
|
zwp_confined_pointer_v1_get_user_data(confined_pointer);
|
||||||
|
|
||||||
|
zwp_confined_pointer_v1_send_confined(host->resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sl_confined_pointer_unconfined(
|
||||||
|
void* data, struct zwp_confined_pointer_v1* confined_pointer) {
|
||||||
|
struct sl_host_confined_pointer* host =
|
||||||
|
zwp_confined_pointer_v1_get_user_data(confined_pointer);
|
||||||
|
|
||||||
|
zwp_confined_pointer_v1_send_unconfined(host->resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sl_confined_pointer_set_region(struct wl_client* client,
|
||||||
|
struct wl_resource* resource,
|
||||||
|
struct wl_resource* region) {
|
||||||
|
struct sl_host_confined_pointer* host = wl_resource_get_user_data(resource);
|
||||||
|
struct sl_host_region* host_region =
|
||||||
|
region ? wl_resource_get_user_data(region) : NULL;
|
||||||
|
|
||||||
|
zwp_confined_pointer_v1_set_region(host->proxy,
|
||||||
|
host_region ? host_region->proxy : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct zwp_confined_pointer_v1_listener sl_confined_pointer_listener = {
|
||||||
|
sl_confined_pointer_confined,
|
||||||
|
sl_confined_pointer_unconfined,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct zwp_confined_pointer_v1_interface
|
||||||
|
sl_confined_pointer_implementation = {
|
||||||
|
sl_confined_pointer_destroy,
|
||||||
|
sl_confined_pointer_set_region,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void sl_pointer_constraints_lock_pointer(struct wl_client* client,
|
||||||
|
struct wl_resource* resource,
|
||||||
|
uint32_t id,
|
||||||
|
struct wl_resource* surface,
|
||||||
|
struct wl_resource* pointer,
|
||||||
|
struct wl_resource* region,
|
||||||
|
uint32_t lifetime) {
|
||||||
|
struct sl_host_pointer_constraints* host =
|
||||||
|
wl_resource_get_user_data(resource);
|
||||||
|
struct wl_resource* locked_pointer_resource =
|
||||||
|
wl_resource_create(client, &zwp_locked_pointer_v1_interface, 1, id);
|
||||||
|
struct sl_host_locked_pointer* locked_pointer_host;
|
||||||
|
|
||||||
|
struct sl_host_surface* host_surface = wl_resource_get_user_data(surface);
|
||||||
|
struct sl_host_pointer* host_pointer = wl_resource_get_user_data(pointer);
|
||||||
|
struct sl_host_region* host_region =
|
||||||
|
region ? wl_resource_get_user_data(region) : NULL;
|
||||||
|
|
||||||
|
locked_pointer_host = malloc(sizeof(struct sl_host_locked_pointer));
|
||||||
|
assert(locked_pointer_host);
|
||||||
|
locked_pointer_host->resource = locked_pointer_resource;
|
||||||
|
locked_pointer_host->ctx = host->ctx;
|
||||||
|
locked_pointer_host->proxy = zwp_pointer_constraints_v1_lock_pointer(
|
||||||
|
host->ctx->pointer_constraints->internal, host_surface->proxy,
|
||||||
|
host_pointer->proxy, host_region ? host_region->proxy : NULL, lifetime);
|
||||||
|
wl_resource_set_implementation(
|
||||||
|
locked_pointer_resource, &sl_locked_pointer_implementation,
|
||||||
|
locked_pointer_host, sl_destroy_host_locked_pointer);
|
||||||
|
zwp_locked_pointer_v1_set_user_data(locked_pointer_host->proxy,
|
||||||
|
locked_pointer_host);
|
||||||
|
zwp_locked_pointer_v1_add_listener(locked_pointer_host->proxy,
|
||||||
|
&sl_locked_pointer_listener,
|
||||||
|
locked_pointer_host);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sl_pointer_constraints_confine_pointer(struct wl_client* client,
|
||||||
|
struct wl_resource* resource,
|
||||||
|
uint32_t id,
|
||||||
|
struct wl_resource* surface,
|
||||||
|
struct wl_resource* pointer,
|
||||||
|
struct wl_resource* region,
|
||||||
|
uint32_t lifetime) {
|
||||||
|
struct sl_host_pointer_constraints* host =
|
||||||
|
wl_resource_get_user_data(resource);
|
||||||
|
struct wl_resource* confined_pointer_resource =
|
||||||
|
wl_resource_create(client, &zwp_confined_pointer_v1_interface, 1, id);
|
||||||
|
struct sl_host_confined_pointer* confined_pointer_host;
|
||||||
|
|
||||||
|
struct sl_host_surface* host_surface = wl_resource_get_user_data(surface);
|
||||||
|
struct sl_host_pointer* host_pointer = wl_resource_get_user_data(pointer);
|
||||||
|
struct sl_host_region* host_region =
|
||||||
|
region ? wl_resource_get_user_data(region) : NULL;
|
||||||
|
|
||||||
|
confined_pointer_host = malloc(sizeof(struct sl_host_confined_pointer));
|
||||||
|
assert(confined_pointer_host);
|
||||||
|
confined_pointer_host->resource = confined_pointer_resource;
|
||||||
|
confined_pointer_host->ctx = host->ctx;
|
||||||
|
confined_pointer_host->proxy = zwp_pointer_constraints_v1_confine_pointer(
|
||||||
|
host->ctx->pointer_constraints->internal, host_surface->proxy,
|
||||||
|
host_pointer->proxy, host_region ? host_region->proxy : NULL, lifetime);
|
||||||
|
wl_resource_set_implementation(
|
||||||
|
confined_pointer_resource, &sl_confined_pointer_implementation,
|
||||||
|
confined_pointer_host, sl_destroy_host_confined_pointer);
|
||||||
|
zwp_confined_pointer_v1_set_user_data(confined_pointer_host->proxy,
|
||||||
|
confined_pointer_host);
|
||||||
|
zwp_confined_pointer_v1_add_listener(confined_pointer_host->proxy,
|
||||||
|
&sl_confined_pointer_listener,
|
||||||
|
confined_pointer_host);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct zwp_pointer_constraints_v1_interface
|
||||||
|
sl_pointer_constraints_implementation = {
|
||||||
|
sl_pointer_constraints_destroy,
|
||||||
|
sl_pointer_constraints_lock_pointer,
|
||||||
|
sl_pointer_constraints_confine_pointer,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void sl_bind_host_pointer_constraints(struct wl_client* client,
|
||||||
|
void* data,
|
||||||
|
uint32_t version,
|
||||||
|
uint32_t id) {
|
||||||
|
struct sl_context* ctx = (struct sl_context*)data;
|
||||||
|
struct sl_pointer_constraints* pointer_constraints = ctx->pointer_constraints;
|
||||||
|
struct sl_host_pointer_constraints* host =
|
||||||
|
malloc(sizeof(struct sl_host_pointer_constraints));
|
||||||
|
|
||||||
|
assert(host);
|
||||||
|
host->ctx = ctx;
|
||||||
|
host->resource =
|
||||||
|
wl_resource_create(client, &zwp_pointer_constraints_v1_interface, 1, id);
|
||||||
|
wl_resource_set_implementation(host->resource,
|
||||||
|
&sl_pointer_constraints_implementation, host,
|
||||||
|
sl_destroy_host_pointer_constraints);
|
||||||
|
host->proxy = wl_registry_bind(wl_display_get_registry(ctx->display),
|
||||||
|
pointer_constraints->id,
|
||||||
|
&zwp_pointer_constraints_v1_interface,
|
||||||
|
wl_resource_get_version(host->resource));
|
||||||
|
zwp_pointer_constraints_v1_set_user_data(host->proxy, host);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sl_global* sl_pointer_constraints_global_create(struct sl_context* ctx) {
|
||||||
|
return sl_global_create(ctx, &zwp_pointer_constraints_v1_interface, 1, ctx,
|
||||||
|
sl_bind_host_pointer_constraints);
|
||||||
|
}
|
@ -290,7 +290,7 @@ static void sl_xdg_toplevel_set_fullscreen(
|
|||||||
struct wl_resource* output_resource) {
|
struct wl_resource* output_resource) {
|
||||||
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
struct sl_host_xdg_toplevel* host = wl_resource_get_user_data(resource);
|
||||||
struct sl_host_output* host_output =
|
struct sl_host_output* host_output =
|
||||||
output_resource ? wl_resource_get_user_data(resource) : NULL;
|
output_resource ? wl_resource_get_user_data(output_resource) : NULL;
|
||||||
|
|
||||||
zxdg_toplevel_v6_set_fullscreen(host->proxy,
|
zxdg_toplevel_v6_set_fullscreen(host->proxy,
|
||||||
host_output ? host_output->proxy : NULL);
|
host_output ? host_output->proxy : NULL);
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "drm-server-protocol.h"
|
#include "drm-server-protocol.h"
|
||||||
#include "keyboard-extension-unstable-v1-client-protocol.h"
|
#include "keyboard-extension-unstable-v1-client-protocol.h"
|
||||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||||
|
#include "pointer-constraints-unstable-v1-client-protocol.h"
|
||||||
#include "relative-pointer-unstable-v1-client-protocol.h"
|
#include "relative-pointer-unstable-v1-client-protocol.h"
|
||||||
#include "text-input-unstable-v1-client-protocol.h"
|
#include "text-input-unstable-v1-client-protocol.h"
|
||||||
#include "viewporter-client-protocol.h"
|
#include "viewporter-client-protocol.h"
|
||||||
@ -74,6 +75,7 @@ enum {
|
|||||||
PROPERTY_WM_CLIENT_LEADER,
|
PROPERTY_WM_CLIENT_LEADER,
|
||||||
PROPERTY_MOTIF_WM_HINTS,
|
PROPERTY_MOTIF_WM_HINTS,
|
||||||
PROPERTY_NET_STARTUP_ID,
|
PROPERTY_NET_STARTUP_ID,
|
||||||
|
PROPERTY_NET_WM_STATE,
|
||||||
PROPERTY_GTK_THEME_VARIANT,
|
PROPERTY_GTK_THEME_VARIANT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -240,8 +242,7 @@ struct sl_sync_point* sl_sync_point_create(int fd) {
|
|||||||
return sync_point;
|
return sync_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sl_sync_point_destroy(struct sl_sync_point* sync_point)
|
void sl_sync_point_destroy(struct sl_sync_point* sync_point) {
|
||||||
{
|
|
||||||
close(sync_point->fd);
|
close(sync_point->fd);
|
||||||
free(sync_point);
|
free(sync_point);
|
||||||
}
|
}
|
||||||
@ -358,7 +359,8 @@ static void sl_set_input_focus(struct sl_context* ctx,
|
|||||||
.type = ctx->atoms[ATOM_WM_PROTOCOLS].value,
|
.type = ctx->atoms[ATOM_WM_PROTOCOLS].value,
|
||||||
.data.data32 =
|
.data.data32 =
|
||||||
{
|
{
|
||||||
ctx->atoms[ATOM_WM_TAKE_FOCUS].value, XCB_CURRENT_TIME,
|
ctx->atoms[ATOM_WM_TAKE_FOCUS].value,
|
||||||
|
XCB_CURRENT_TIME,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -527,7 +529,8 @@ static void sl_internal_xdg_toplevel_close(
|
|||||||
.type = window->ctx->atoms[ATOM_WM_PROTOCOLS].value,
|
.type = window->ctx->atoms[ATOM_WM_PROTOCOLS].value,
|
||||||
.data.data32 =
|
.data.data32 =
|
||||||
{
|
{
|
||||||
window->ctx->atoms[ATOM_WM_DELETE_WINDOW].value, XCB_CURRENT_TIME,
|
window->ctx->atoms[ATOM_WM_DELETE_WINDOW].value,
|
||||||
|
XCB_CURRENT_TIME,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -748,17 +751,20 @@ void sl_window_update(struct sl_window* window) {
|
|||||||
window->max_width / ctx->scale,
|
window->max_width / ctx->scale,
|
||||||
window->max_height / ctx->scale);
|
window->max_height / ctx->scale);
|
||||||
}
|
}
|
||||||
|
if (window->maximized) {
|
||||||
|
zxdg_toplevel_v6_set_maximized(window->xdg_toplevel);
|
||||||
|
}
|
||||||
} else if (!window->xdg_popup) {
|
} else if (!window->xdg_popup) {
|
||||||
struct zxdg_positioner_v6* positioner;
|
struct zxdg_positioner_v6* positioner;
|
||||||
|
|
||||||
positioner = zxdg_shell_v6_create_positioner(ctx->xdg_shell->internal);
|
positioner = zxdg_shell_v6_create_positioner(ctx->xdg_shell->internal);
|
||||||
assert(positioner);
|
assert(positioner);
|
||||||
zxdg_positioner_v6_set_anchor(positioner,
|
zxdg_positioner_v6_set_anchor(
|
||||||
ZXDG_POSITIONER_V6_ANCHOR_TOP |
|
positioner,
|
||||||
ZXDG_POSITIONER_V6_ANCHOR_LEFT);
|
ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_LEFT);
|
||||||
zxdg_positioner_v6_set_gravity(positioner,
|
zxdg_positioner_v6_set_gravity(
|
||||||
ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
|
positioner,
|
||||||
ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
|
ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
|
||||||
zxdg_positioner_v6_set_anchor_rect(
|
zxdg_positioner_v6_set_anchor_rect(
|
||||||
positioner, (window->x - parent->x) / ctx->scale,
|
positioner, (window->x - parent->x) / ctx->scale,
|
||||||
(window->y - parent->y) / ctx->scale, 1, 1);
|
(window->y - parent->y) / ctx->scale, 1, 1);
|
||||||
@ -1102,6 +1108,18 @@ static void sl_registry_handler(void* data,
|
|||||||
ctx->relative_pointer_manager = relative_pointer;
|
ctx->relative_pointer_manager = relative_pointer;
|
||||||
relative_pointer->host_global =
|
relative_pointer->host_global =
|
||||||
sl_relative_pointer_manager_global_create(ctx);
|
sl_relative_pointer_manager_global_create(ctx);
|
||||||
|
} else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
|
||||||
|
struct sl_pointer_constraints* pointer_constraints =
|
||||||
|
malloc(sizeof(struct sl_pointer_constraints));
|
||||||
|
assert(pointer_constraints);
|
||||||
|
pointer_constraints->ctx = ctx;
|
||||||
|
pointer_constraints->id = id;
|
||||||
|
pointer_constraints->internal = wl_registry_bind(
|
||||||
|
registry, id, &zwp_pointer_constraints_v1_interface, 1);
|
||||||
|
assert(!ctx->pointer_constraints);
|
||||||
|
ctx->pointer_constraints = pointer_constraints;
|
||||||
|
pointer_constraints->host_global =
|
||||||
|
sl_pointer_constraints_global_create(ctx);
|
||||||
} else if (strcmp(interface, "wl_data_device_manager") == 0) {
|
} else if (strcmp(interface, "wl_data_device_manager") == 0) {
|
||||||
struct sl_data_device_manager* data_device_manager =
|
struct sl_data_device_manager* data_device_manager =
|
||||||
malloc(sizeof(struct sl_data_device_manager));
|
malloc(sizeof(struct sl_data_device_manager));
|
||||||
@ -1295,6 +1313,12 @@ static void sl_registry_remover(void* data,
|
|||||||
ctx->relative_pointer_manager = NULL;
|
ctx->relative_pointer_manager = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (ctx->pointer_constraints && ctx->pointer_constraints->id == id) {
|
||||||
|
sl_global_destroy(ctx->pointer_constraints->host_global);
|
||||||
|
free(ctx->pointer_constraints);
|
||||||
|
ctx->pointer_constraints = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
wl_list_for_each(output, &ctx->outputs, link) {
|
wl_list_for_each(output, &ctx->outputs, link) {
|
||||||
if (output->id == id) {
|
if (output->id == id) {
|
||||||
sl_global_destroy(output->host_global);
|
sl_global_destroy(output->host_global);
|
||||||
@ -1365,6 +1389,7 @@ static void sl_create_window(struct sl_context* ctx,
|
|||||||
window->managed = 0;
|
window->managed = 0;
|
||||||
window->realized = 0;
|
window->realized = 0;
|
||||||
window->activated = 0;
|
window->activated = 0;
|
||||||
|
window->maximized = 0;
|
||||||
window->allow_resize = 1;
|
window->allow_resize = 1;
|
||||||
window->transient_for = XCB_WINDOW_NONE;
|
window->transient_for = XCB_WINDOW_NONE;
|
||||||
window->client_leader = XCB_WINDOW_NONE;
|
window->client_leader = XCB_WINDOW_NONE;
|
||||||
@ -1533,12 +1558,15 @@ static void sl_handle_map_request(struct sl_context* ctx,
|
|||||||
{PROPERTY_WM_CLIENT_LEADER, ctx->atoms[ATOM_WM_CLIENT_LEADER].value},
|
{PROPERTY_WM_CLIENT_LEADER, ctx->atoms[ATOM_WM_CLIENT_LEADER].value},
|
||||||
{PROPERTY_MOTIF_WM_HINTS, ctx->atoms[ATOM_MOTIF_WM_HINTS].value},
|
{PROPERTY_MOTIF_WM_HINTS, ctx->atoms[ATOM_MOTIF_WM_HINTS].value},
|
||||||
{PROPERTY_NET_STARTUP_ID, ctx->atoms[ATOM_NET_STARTUP_ID].value},
|
{PROPERTY_NET_STARTUP_ID, ctx->atoms[ATOM_NET_STARTUP_ID].value},
|
||||||
|
{PROPERTY_NET_WM_STATE, ctx->atoms[ATOM_NET_WM_STATE].value},
|
||||||
{PROPERTY_GTK_THEME_VARIANT, ctx->atoms[ATOM_GTK_THEME_VARIANT].value},
|
{PROPERTY_GTK_THEME_VARIANT, ctx->atoms[ATOM_GTK_THEME_VARIANT].value},
|
||||||
};
|
};
|
||||||
xcb_get_geometry_cookie_t geometry_cookie;
|
xcb_get_geometry_cookie_t geometry_cookie;
|
||||||
xcb_get_property_cookie_t property_cookies[ARRAY_SIZE(properties)];
|
xcb_get_property_cookie_t property_cookies[ARRAY_SIZE(properties)];
|
||||||
struct sl_wm_size_hints size_hints = {0};
|
struct sl_wm_size_hints size_hints = {0};
|
||||||
struct sl_mwm_hints mwm_hints = {0};
|
struct sl_mwm_hints mwm_hints = {0};
|
||||||
|
xcb_atom_t* reply_atoms;
|
||||||
|
bool maximize_h = false, maximize_v = false;
|
||||||
uint32_t values[5];
|
uint32_t values[5];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -1617,7 +1645,8 @@ static void sl_handle_map_request(struct sl_context* ctx,
|
|||||||
break;
|
break;
|
||||||
case PROPERTY_WM_NORMAL_HINTS:
|
case PROPERTY_WM_NORMAL_HINTS:
|
||||||
if (xcb_get_property_value_length(reply) >= sizeof(size_hints))
|
if (xcb_get_property_value_length(reply) >= sizeof(size_hints))
|
||||||
memcpy(&size_hints, xcb_get_property_value(reply), sizeof(size_hints));
|
memcpy(&size_hints, xcb_get_property_value(reply),
|
||||||
|
sizeof(size_hints));
|
||||||
break;
|
break;
|
||||||
case PROPERTY_WM_CLIENT_LEADER:
|
case PROPERTY_WM_CLIENT_LEADER:
|
||||||
if (xcb_get_property_value_length(reply) >= 4)
|
if (xcb_get_property_value_length(reply) >= 4)
|
||||||
@ -1631,6 +1660,24 @@ static void sl_handle_map_request(struct sl_context* ctx,
|
|||||||
window->startup_id = strndup(xcb_get_property_value(reply),
|
window->startup_id = strndup(xcb_get_property_value(reply),
|
||||||
xcb_get_property_value_length(reply));
|
xcb_get_property_value_length(reply));
|
||||||
break;
|
break;
|
||||||
|
case PROPERTY_NET_WM_STATE:
|
||||||
|
reply_atoms = xcb_get_property_value(reply);
|
||||||
|
for (i = 0;
|
||||||
|
i < xcb_get_property_value_length(reply) / sizeof(xcb_atom_t);
|
||||||
|
++i) {
|
||||||
|
if (reply_atoms[i] ==
|
||||||
|
ctx->atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ].value) {
|
||||||
|
maximize_h = true;
|
||||||
|
} else if (reply_atoms[i] ==
|
||||||
|
ctx->atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT].value) {
|
||||||
|
maximize_v = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Neither wayland not CrOS support 1D maximizing, so sommelier will
|
||||||
|
// only consider a window maximized if both dimensions are. This
|
||||||
|
// behaviour is consistent with sl_handle_client_message().
|
||||||
|
window->maximized = maximize_h && maximize_v;
|
||||||
|
break;
|
||||||
case PROPERTY_GTK_THEME_VARIANT:
|
case PROPERTY_GTK_THEME_VARIANT:
|
||||||
if (xcb_get_property_value_length(reply) >= 4)
|
if (xcb_get_property_value_length(reply) >= 4)
|
||||||
window->dark_frame = !strcmp(xcb_get_property_value(reply), "dark");
|
window->dark_frame = !strcmp(xcb_get_property_value(reply), "dark");
|
||||||
@ -2652,7 +2699,10 @@ static void sl_send_data(struct sl_context* ctx, xcb_atom_t data_type) {
|
|||||||
switch (ctx->data_driver) {
|
switch (ctx->data_driver) {
|
||||||
case DATA_DRIVER_VIRTWL: {
|
case DATA_DRIVER_VIRTWL: {
|
||||||
struct virtwl_ioctl_new new_pipe = {
|
struct virtwl_ioctl_new new_pipe = {
|
||||||
.type = VIRTWL_IOCTL_NEW_PIPE_READ, .fd = -1, .flags = 0, .size = 0,
|
.type = VIRTWL_IOCTL_NEW_PIPE_READ,
|
||||||
|
.fd = -1,
|
||||||
|
.flags = 0,
|
||||||
|
.size = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
rv = ioctl(ctx->virtwl_fd, VIRTWL_IOCTL_NEW, &new_pipe);
|
rv = ioctl(ctx->virtwl_fd, VIRTWL_IOCTL_NEW, &new_pipe);
|
||||||
@ -3198,7 +3248,6 @@ static int sl_handle_virtwl_ctx_event(int fd, uint32_t mask, void* data) {
|
|||||||
if (ioctl_recv->fds[fd_count] < 0)
|
if (ioctl_recv->fds[fd_count] < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fd_count) {
|
if (fd_count) {
|
||||||
struct cmsghdr* cmsg;
|
struct cmsghdr* cmsg;
|
||||||
|
|
||||||
@ -3682,7 +3731,6 @@ int main(int argc, char **argv) {
|
|||||||
peer_cmd_prefix = PEER_CMD_PREFIX;
|
peer_cmd_prefix = PEER_CMD_PREFIX;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fprintf(stderr, "peer_cmd_prefix = '%s'\n", peer_cmd_prefix);
|
|
||||||
if (peer_cmd_prefix) {
|
if (peer_cmd_prefix) {
|
||||||
peer_cmd_prefix_str = sl_xasprintf("%s", peer_cmd_prefix);
|
peer_cmd_prefix_str = sl_xasprintf("%s", peer_cmd_prefix);
|
||||||
|
|
||||||
@ -3692,8 +3740,8 @@ int main(int argc, char **argv) {
|
|||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
args[i++] = argv[0];
|
args[i++] = argv[0];
|
||||||
peer_pid_str = sl_xasprintf("--peer-pid=%d", ucred.pid);
|
peer_pid_str = sl_xasprintf("--peer-pid=%d", ucred.pid);
|
||||||
args[i++] = peer_pid_str;
|
args[i++] = peer_pid_str;
|
||||||
@ -3778,7 +3826,10 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
if (virtwl_device) {
|
if (virtwl_device) {
|
||||||
struct virtwl_ioctl_new new_ctx = {
|
struct virtwl_ioctl_new new_ctx = {
|
||||||
.type = VIRTWL_IOCTL_NEW_CTX, .fd = -1, .flags = 0, .size = 0,
|
.type = VIRTWL_IOCTL_NEW_CTX,
|
||||||
|
.fd = -1,
|
||||||
|
.flags = 0,
|
||||||
|
.size = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.virtwl_fd = open(virtwl_device, O_RDWR);
|
ctx.virtwl_fd = open(virtwl_device, O_RDWR);
|
||||||
@ -3808,7 +3859,6 @@ int main(int argc, char **argv) {
|
|||||||
strerror(errno));
|
strerror(errno));
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
//fprintf(stderr, "ioctl(%d, VIRTWL_IOCTL_NEW_CTX) -> %d\n", ctx.virtwl_fd, new_ctx.fd);
|
|
||||||
|
|
||||||
ctx.virtwl_ctx_fd = new_ctx.fd;
|
ctx.virtwl_ctx_fd = new_ctx.fd;
|
||||||
|
|
||||||
@ -3864,7 +3914,9 @@ int main(int argc, char **argv) {
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
.dmabuf =
|
.dmabuf =
|
||||||
{
|
{
|
||||||
.width = 0, .height = 0, .format = 0,
|
.width = 0,
|
||||||
|
.height = 0,
|
||||||
|
.format = 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (ioctl(ctx.virtwl_fd, VIRTWL_IOCTL_NEW, &new_dmabuf) == -1 &&
|
if (ioctl(ctx.virtwl_fd, VIRTWL_IOCTL_NEW, &new_dmabuf) == -1 &&
|
||||||
|
@ -41,6 +41,7 @@ struct sl_linux_dmabuf;
|
|||||||
struct sl_keyboard_extension;
|
struct sl_keyboard_extension;
|
||||||
struct sl_text_input_manager;
|
struct sl_text_input_manager;
|
||||||
struct sl_relative_pointer_manager;
|
struct sl_relative_pointer_manager;
|
||||||
|
struct sl_pointer_constraints;
|
||||||
struct sl_window;
|
struct sl_window;
|
||||||
struct zaura_shell;
|
struct zaura_shell;
|
||||||
struct zcr_keyboard_extension_v1;
|
struct zcr_keyboard_extension_v1;
|
||||||
@ -105,6 +106,7 @@ struct sl_context {
|
|||||||
struct sl_keyboard_extension* keyboard_extension;
|
struct sl_keyboard_extension* keyboard_extension;
|
||||||
struct sl_text_input_manager* text_input_manager;
|
struct sl_text_input_manager* text_input_manager;
|
||||||
struct sl_relative_pointer_manager* relative_pointer_manager;
|
struct sl_relative_pointer_manager* relative_pointer_manager;
|
||||||
|
struct sl_pointer_constraints* pointer_constraints;
|
||||||
struct wl_list outputs;
|
struct wl_list outputs;
|
||||||
struct wl_list seats;
|
struct wl_list seats;
|
||||||
struct wl_event_source* display_event_source;
|
struct wl_event_source* display_event_source;
|
||||||
@ -248,6 +250,12 @@ struct sl_host_surface {
|
|||||||
struct wl_list busy_buffers;
|
struct wl_list busy_buffers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sl_host_region {
|
||||||
|
struct sl_context* ctx;
|
||||||
|
struct wl_resource* resource;
|
||||||
|
struct wl_region* proxy;
|
||||||
|
};
|
||||||
|
|
||||||
struct sl_host_buffer {
|
struct sl_host_buffer {
|
||||||
struct wl_resource* resource;
|
struct wl_resource* resource;
|
||||||
struct wl_buffer* proxy;
|
struct wl_buffer* proxy;
|
||||||
@ -351,6 +359,13 @@ struct sl_text_input_manager {
|
|||||||
struct zwp_text_input_manager_v1* internal;
|
struct zwp_text_input_manager_v1* internal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sl_pointer_constraints {
|
||||||
|
struct sl_context* ctx;
|
||||||
|
uint32_t id;
|
||||||
|
struct sl_global* host_global;
|
||||||
|
struct zwp_pointer_constraints_v1* internal;
|
||||||
|
};
|
||||||
|
|
||||||
struct sl_viewporter {
|
struct sl_viewporter {
|
||||||
struct sl_context* ctx;
|
struct sl_context* ctx;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
@ -445,6 +460,7 @@ struct sl_window {
|
|||||||
int managed;
|
int managed;
|
||||||
int realized;
|
int realized;
|
||||||
int activated;
|
int activated;
|
||||||
|
int maximized;
|
||||||
int allow_resize;
|
int allow_resize;
|
||||||
xcb_window_t transient_for;
|
xcb_window_t transient_for;
|
||||||
xcb_window_t client_leader;
|
xcb_window_t client_leader;
|
||||||
@ -514,6 +530,8 @@ struct sl_global* sl_drm_global_create(struct sl_context* ctx);
|
|||||||
|
|
||||||
struct sl_global* sl_text_input_manager_global_create(struct sl_context* ctx);
|
struct sl_global* sl_text_input_manager_global_create(struct sl_context* ctx);
|
||||||
|
|
||||||
|
struct sl_global* sl_pointer_constraints_global_create(struct sl_context* ctx);
|
||||||
|
|
||||||
void sl_set_display_implementation(struct sl_context* ctx);
|
void sl_set_display_implementation(struct sl_context* ctx);
|
||||||
|
|
||||||
struct sl_mmap* sl_mmap_create(int fd,
|
struct sl_mmap* sl_mmap_create(int fd,
|
||||||
|
Loading…
Reference in New Issue
Block a user