New upstream version 22.1.8

This commit is contained in:
su-fang 2023-04-21 14:17:29 +08:00
parent 48258f0cc7
commit decbdc3bfd
164 changed files with 6669 additions and 3238 deletions

View File

@ -26,7 +26,7 @@ gcc-core,\
meson,\
ninja,\
pkg-config,\
python3,\
python38,\
windowsdriproto,\
xorgproto,\
libepoxy-devel,\
@ -58,10 +58,11 @@ libxcb-render-util-devel,\
libxcb-shape-devel,\
libxcb-util-devel,\
libxcb-xkb-devel,\
libxcvt-devel,\
libxkbfile-devel,\
font-util,\
khronos-opengl-registry,\
python3-lxml,\
python38-lxml,\
xkbcomp-devel,\
xkeyboard-config,\
xtrans"
@ -72,7 +73,7 @@ cache:
- '%CYGWIN_ROOT%\home\%USERNAME%\.ccache'
build_script:
- SET PATH=%CYGWIN_ROOT%/bin
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Dxvfb=true build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Dxvfb=true -Dglamor=false build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson configure build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; ninja -C build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; ccache -s"'

82
.gitignore vendored Normal file
View File

@ -0,0 +1,82 @@
#
# X.Org module default exclusion patterns
# The next section if for module specific patterns
#
# Do not edit the following section
# GNU Build System (Autotools)
aclocal.m4
autom4te.cache/
autoscan.log
ChangeLog
compile
config.guess
config.h
config.h.in
config.log
config-ml.in
config.py
config.status
config.status.lineno
config.sub
configure
configure.scan
depcomp
.deps/
INSTALL
install-sh
.libs/
libtool
libtool.m4
ltmain.sh
lt~obsolete.m4
ltoptions.m4
ltsugar.m4
ltversion.m4
Makefile
Makefile.in
mdate-sh
missing
mkinstalldirs
*.pc
py-compile
stamp-h?
symlink-tree
test-driver
texinfo.tex
ylwrap
# Do not edit the following section
# Edit Compile Debug Document Distribute
*~
*.[0-9]
*.[0-9]x
*.bak
*.bin
core
*.dll
*.exe
*-ISO*.bdf
*-JIS*.bdf
*-KOI8*.bdf
*.kld
*.ko
*.ko.cmd
*.lai
*.l[oa]
*.[oa]
*.obj
*.patch
*.so
*.pcf.gz
*.pdb
*.tar.bz2
*.tar.gz
#
# Add & Override patterns for xserver
#
# Edit the following section as needed
# For example, !report.pc overrides *.pc. See 'man gitignore'
#
doltcompile
doltlibtool
xserver.ent

74
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,74 @@
# FDO_DISTRIBUTION_TAG is the tag of the docker image used for the build jobs.
# If the image doesn't exist yet, the docker-image stage generates it.
#
# In order to generate a new image, one should generally change the tag.
# While removing the image from the registry would also work, that's not
# recommended except for ephemeral images during development: Replacing an
# image after a significant amount of time might pull in newer versions of
# gcc/clang or other packages, which might break the build with older commits
# using the same tag.
variables:
FDO_UPSTREAM_REPO: xorg/xserver
FDO_DISTRIBUTION_VERSION: buster-slim
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} bash .gitlab-ci/debian-install.sh'
FDO_DISTRIBUTION_TAG: "2021-12-13-no-mingw"
include:
- project: 'freedesktop/ci-templates'
ref: 4f06663cd1507136a0f8440925a2521098adb298
file: '/templates/debian.yml'
stages:
- docker-image
- build-and-test
.ci-run-policy:
# Retry jobs after runner system failures
retry:
max: 2
when:
- runner_system_failure
# Cancel CI run if a newer commit is pushed to the same branch
interruptible: true
debian-buster:
extends:
- .fdo.container-build@debian
- .ci-run-policy
stage: docker-image
variables:
GIT_STRATEGY: none
.common-build-and-test:
extends:
- .fdo.distribution-image@debian
- .ci-run-policy
stage: build-and-test
artifacts:
when: on_failure
paths:
- build/test/piglit-results/
variables:
CCACHE_COMPILERCHECK: content
CCACHE_DIR: /cache/xserver/cache
LC_ALL: C.UTF-8
before_script:
- export CCACHE_BASEDIR="$PWD"
- export PATH="/usr/lib/ccache:$PATH"
- ccache --show-stats
after_script:
- ccache --show-stats
meson:
extends: .common-build-and-test
script:
- meson -Dc_args="-fno-common" -Dprefix=/usr -Dxvfb=false -Dwerror=true $MESON_EXTRA_OPTIONS build/
- ninja -j${FDO_CI_CONCURRENT:-4} -C build/ dist
- PIGLIT_DIR=/root/piglit XTEST_DIR=/root/xts ninja -j${FDO_CI_CONCURRENT:-4} -C build/ test
- .gitlab-ci/manpages-check
meson-noglamor:
extends: meson
variables:
MESON_EXTRA_OPTIONS: >
-Dglamor=false

View File

@ -0,0 +1,181 @@
#!/bin/bash
set -e
set -o xtrace
# Packages which are needed by this script, but not for the xserver build
EPHEMERAL="
libcairo2-dev
libevdev-dev
libexpat-dev
libgles2-mesa-dev
libinput-dev
libxkbcommon-dev
x11-utils
x11-xserver-utils
xauth
xvfb
"
apt-get install -y \
$EPHEMERAL \
autoconf \
automake \
bison \
build-essential \
ca-certificates \
ccache \
flex \
git \
libaudit-dev \
libbsd-dev \
libcairo2 \
libdbus-1-dev \
libdmx-dev \
libdrm-dev \
libegl1-mesa-dev \
libepoxy-dev \
libevdev2 \
libexpat1 \
libffi-dev \
libgbm-dev \
libgcrypt-dev \
libgl1-mesa-dev \
libgles2 \
libglx-mesa0 \
libinput10 \
libnvidia-egl-wayland-dev \
libpciaccess-dev \
libpixman-1-dev \
libselinux1-dev \
libsystemd-dev \
libtool \
libudev-dev \
libunwind-dev \
libx11-dev \
libx11-xcb-dev \
libxau-dev \
libxaw7-dev \
libxcb-glx0-dev \
libxcb-icccm4-dev \
libxcb-image0-dev \
libxcb-keysyms1-dev \
libxcb-randr0-dev \
libxcb-render-util0-dev \
libxcb-render0-dev \
libxcb-shape0-dev \
libxcb-shm0-dev \
libxcb-util0-dev \
libxcb-xf86dri0-dev \
libxcb-xkb-dev \
libxcb-xv0-dev \
libxcb1-dev \
libxdmcp-dev \
libxext-dev \
libxfixes-dev \
libxfont-dev \
libxi-dev \
libxinerama-dev \
libxkbcommon0 \
libxkbfile-dev \
libxmu-dev \
libxmuu-dev \
libxpm-dev \
libxrender-dev \
libxres-dev \
libxshmfence-dev \
libxt-dev \
libxtst-dev \
libxv-dev \
mesa-common-dev \
meson \
nettle-dev \
pkg-config \
python3-mako \
python3-numpy \
python3-six \
xfonts-utils \
xkb-data \
xtrans-dev \
xutils-dev
cd /root
# xserver requires libxcvt
git clone https://gitlab.freedesktop.org/xorg/lib/libxcvt.git --depth 1 --branch=libxcvt-0.1.0
cd libxcvt
meson _build
ninja -C _build -j${FDO_CI_CONCURRENT:-4} install
cd ..
rm -rf libxcvt
# xserver requires xorgproto >= 2021.4.99.2 for XI 2.3.99.1
git clone https://gitlab.freedesktop.org/xorg/proto/xorgproto.git --depth 1 --branch=xorgproto-2021.4.99.2
pushd xorgproto
./autogen.sh
make -j${FDO_CI_CONCURRENT:-4} install
popd
rm -rf xorgproto
# weston 9.0 requires libwayland >= 1.18
git clone https://gitlab.freedesktop.org/wayland/wayland.git --depth 1 --branch=1.18.0
cd wayland
meson _build -D{documentation,dtd_validation}=false
ninja -C _build -j${FDO_CI_CONCURRENT:-4} install
cd ..
rm -rf wayland
# Xwayland requires wayland-protocols >= 1.22, but Debian buster has 1.17 only
git clone https://gitlab.freedesktop.org/wayland/wayland-protocols.git --depth 1 --branch=1.22
cd wayland-protocols
./autogen.sh
make -j${FDO_CI_CONCURRENT:-4} install
cd ..
rm -rf wayland-protocols
# Xwayland requires weston > 5.0, but Debian buster has 5.0 only
git clone https://gitlab.freedesktop.org/wayland/weston.git --depth 1 --branch=9.0
cd weston
meson _build -Dbackend-{drm,drm-screencast-vaapi,fbdev,rdp,wayland,x11}=false \
-Dbackend-default=headless -Dcolor-management-{colord,lcms}=false \
-Ddemo-clients=false -Dimage-{jpeg,webp}=false \
-D{pipewire,remoting,screenshare,test-junit-xml,wcap-decode,weston-launch,xwayland}=false \
-Dshell-{fullscreen,ivi,kiosk}=false -Dsimple-clients=
ninja -C _build -j${FDO_CI_CONCURRENT:-4} install
cd ..
rm -rf weston
git clone https://gitlab.freedesktop.org/mesa/piglit.git --depth 1
git clone https://gitlab.freedesktop.org/xorg/test/xts --depth 1
cd xts
./autogen.sh
xvfb-run make -j${FDO_CI_CONCURRENT:-4}
cd ..
git clone https://gitlab.freedesktop.org/xorg/test/rendercheck --depth 1
cd rendercheck
meson build
ninja -j${FDO_CI_CONCURRENT:-4} -C build install
cd ..
rm -rf piglit/.git xts/.git piglit/tests/spec/ rendercheck/
echo '[xts]' > piglit/piglit.conf
echo 'path=/root/xts' >> piglit/piglit.conf
find -name \*.a -o -name \*.o -o -name \*.c -o -name \*.h -o -name \*.la\* | xargs rm
strip xts/xts5/*/.libs/*
# Running meson dist requires xkbcomp 1.4.1 or newer, but Debian buster has 1.4.0 only
git clone https://gitlab.freedesktop.org/xorg/app/xkbcomp.git --depth 1 --branch=xkbcomp-1.4.1
cd xkbcomp
./autogen.sh --datarootdir=/usr/share
make -j${FDO_CI_CONCURRENT:-4} install
cd ..
rm -rf xkbcomp
apt-get purge -y \
$EPHEMERAL
apt-get autoremove -y --purge

33
.gitlab-ci/manpages-check Executable file
View File

@ -0,0 +1,33 @@
#!/bin/sh
find build/ -regex ".*\.[1-9]$" -exec grep -E \
@vendorversion@\|\
@xorgversion@\|\
@xservername@\|\
@xconfigfile@\|\
@projectroot@\|\
@apploaddir@\|\
@appmansuffix@\|\
@drivermansuffix@\|\
@adminmansuffix@\|\
@libmansuffix@\|\
@miscmansuffix@\|\
@filemansuffix@\|\
@logdir@\|\
@datadir@\|\
@mandir@\|\
@sysconfdir@\|\
@xconfigdir@\|\
@xkbdir@\|\
@XKB_DFLT_RULES@\|\
@XKB_DFLT_MODEL@\|\
@XKB_DFLT_LAYOUT@\|\
@XKB_DFLT_VARIANT@\|\
@XKB_DFLT_OPTIONS@\|\
@bundle_id_prefix@\|\
@modulepath@\|\
@suid_wrapper_dir@\|\
@default_font_path@\
'{}' + && { echo "Missing manpage substitutions detected!" >&2 ; exit 1; }
exit 0

View File

@ -138,9 +138,15 @@ ProcGEDispatch(ClientPtr client)
static int _X_COLD
SProcGEDispatch(ClientPtr client)
{
GEClientInfoPtr pGEClient = GEGetClient(client);
REQUEST(xGEReq);
if (stuff->ReqType >= GENumberRequests)
if (pGEClient->major_version >= ARRAY_SIZE(version_requests))
return BadRequest;
if (stuff->ReqType > version_requests[pGEClient->major_version])
return BadRequest;
return (*SProcGEVector[stuff->ReqType]) (client);
}

View File

@ -1051,7 +1051,7 @@ ScreenSaverSetAttributes(ClientPtr client)
pVlist++;
}
if (pPriv->attr)
FreeScreenAttr(pPriv->attr);
FreeResource(pPriv->attr->resource, AttrType);
pPriv->attr = pAttr;
pAttr->resource = FakeClientID(client->index);
if (!AddResource(pAttr->resource, AttrType, (void *) pAttr))
@ -1351,8 +1351,8 @@ SProcScreenSaverSuspend(ClientPtr client)
REQUEST(xScreenSaverSuspendReq);
swaps(&stuff->length);
swapl(&stuff->suspend);
REQUEST_SIZE_MATCH(xScreenSaverSuspendReq);
swapl(&stuff->suspend);
return ProcScreenSaverSuspend(client);
}

View File

@ -37,8 +37,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define USE_SEL offsetof(SELinuxSubjectRec, sel_use_sid)
typedef struct {
security_context_t octx;
security_context_t dctx;
char *octx;
char *dctx;
CARD32 octx_len;
CARD32 dctx_len;
CARD32 id;
@ -48,10 +48,10 @@ typedef struct {
* Extension Dispatch
*/
static security_context_t
static char *
SELinuxCopyContext(char *ptr, unsigned len)
{
security_context_t copy = malloc(len + 1);
char *copy = malloc(len + 1);
if (!copy)
return NULL;
@ -84,7 +84,7 @@ static int
SELinuxSendContextReply(ClientPtr client, security_id_t sid)
{
SELinuxGetContextReply rep;
security_context_t ctx = NULL;
char *ctx = NULL;
int len = 0;
if (sid) {
@ -117,7 +117,7 @@ ProcSELinuxSetCreateContext(ClientPtr client, unsigned offset)
{
PrivateRec **privPtr = &client->devPrivates;
security_id_t *pSid;
security_context_t ctx = NULL;
char *ctx = NULL;
char *ptr;
int rc;
@ -165,7 +165,7 @@ ProcSELinuxGetCreateContext(ClientPtr client, unsigned offset)
static int
ProcSELinuxSetDeviceContext(ClientPtr client)
{
security_context_t ctx;
char *ctx;
security_id_t sid;
DeviceIntPtr dev;
SELinuxSubjectRec *subj;

View File

@ -114,7 +114,7 @@ SELinuxLabelClient(ClientPtr client)
int fd = XaceGetConnectionNumber(client);
SELinuxSubjectRec *subj;
SELinuxObjectRec *obj;
security_context_t ctx;
char *ctx;
subj = dixLookupPrivate(&client->devPrivates, subjectKey);
obj = dixLookupPrivate(&client->devPrivates, objectKey);
@ -169,7 +169,7 @@ SELinuxLabelInitial(void)
XaceScreenAccessRec srec;
SELinuxSubjectRec *subj;
SELinuxObjectRec *obj;
security_context_t ctx;
char *ctx;
void *unused;
/* Do the serverClient */
@ -773,7 +773,7 @@ SELinuxResourceState(CallbackListPtr *pcbl, void *unused, void *calldata)
subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey);
if (subj->sid) {
security_context_t ctx;
char *ctx;
int rc = avc_sid_to_context_raw(subj->sid, &ctx);
if (rc < 0)
@ -791,7 +791,7 @@ SELinuxResourceState(CallbackListPtr *pcbl, void *unused, void *calldata)
obj = dixLookupPrivate(&pWin->devPrivates, objectKey);
if (obj->sid) {
security_context_t ctx;
char *ctx;
int rc = avc_sid_to_context_raw(obj->sid, &ctx);
if (rc < 0)
@ -847,7 +847,7 @@ void
SELinuxFlaskInit(void)
{
struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *) 0 };
security_context_t ctx;
char *ctx;
int ret = TRUE;
switch (selinuxEnforcingState) {

View File

@ -97,7 +97,7 @@ static int
SELinuxAtomToSIDLookup(Atom atom, SELinuxObjectRec * obj, int map, int polymap)
{
const char *name = NameForAtom(atom);
security_context_t ctx;
char *ctx;
int rc = Success;
obj->poly = 1;
@ -255,7 +255,7 @@ SELinuxEventToSID(unsigned type, security_id_t sid_of_window,
{
const char *name = LookupEventName(type);
security_id_t sid;
security_context_t ctx;
char *ctx;
type &= 127;
@ -291,7 +291,7 @@ SELinuxEventToSID(unsigned type, security_id_t sid_of_window,
int
SELinuxExtensionToSID(const char *name, security_id_t * sid_rtn)
{
security_context_t ctx;
char *ctx;
/* Look in the mappings of extension names to contexts */
if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EXT) < 0) {
@ -347,10 +347,10 @@ SELinuxTypeToClass(RESTYPE type)
return (security_class_t) (unsigned long) tmp;
}
security_context_t
char *
SELinuxDefaultClientLabel(void)
{
security_context_t ctx;
char *ctx;
if (selabel_lookup_raw(label_hnd, &ctx, "remote", SELABEL_X_CLIENT) < 0)
FatalError("SELinux: failed to look up remote-client context\n");

View File

@ -99,7 +99,7 @@ int
security_class_t SELinuxTypeToClass(RESTYPE type);
security_context_t SELinuxDefaultClientLabel(void);
char *SELinuxDefaultClientLabel(void);
void
SELinuxLabelInit(void);

View File

@ -502,10 +502,11 @@ XTestSwapFakeInput(ClientPtr client, xReq * req)
nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent);
for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) {
int evtype = ev->u.u.type & 0177;
/* Swap event */
proc = EventSwapVector[ev->u.u.type & 0177];
proc = EventSwapVector[evtype];
/* no swapping proc; invalid event type? */
if (!proc || proc == NotImplemented) {
if (!proc || proc == NotImplemented || evtype == GenericEvent) {
client->errorValue = ev->u.u.type;
return BadValue;
}

View File

@ -811,8 +811,10 @@ XvdiSelectVideoNotify(ClientPtr client, DrawablePtr pDraw, BOOL onoff)
tpn = pn;
while (tpn) {
if (tpn->client == client) {
if (!onoff)
if (!onoff) {
tpn->client = NULL;
FreeResource(tpn->id, XvRTVideoNotify);
}
return Success;
}
if (!tpn->client)

View File

@ -464,8 +464,11 @@ ProcXChangeFeedbackControl(ClientPtr client)
break;
case StringFeedbackClass:
{
xStringFeedbackCtl *f = ((xStringFeedbackCtl *) &stuff[1]);
xStringFeedbackCtl *f;
REQUEST_AT_LEAST_EXTRA_SIZE(xChangeFeedbackControlReq,
sizeof(xStringFeedbackCtl));
f = ((xStringFeedbackCtl *) &stuff[1]);
if (client->swapped) {
if (len < bytes_to_int32(sizeof(xStringFeedbackCtl)))
return BadLength;

View File

@ -95,6 +95,7 @@ SOFTWARE.
#include "exevents.h"
#include "extnsionst.h"
#include "exglobals.h"
#include "eventstr.h"
#include "dixevents.h" /* DeliverFocusedEvent */
#include "dixgrabs.h" /* CreateGrab() */
#include "scrnintstr.h"
@ -168,6 +169,49 @@ IsTouchEvent(InternalEvent *event)
return FALSE;
}
Bool
IsGestureEvent(InternalEvent *event)
{
switch (event->any.type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return TRUE;
default:
break;
}
return FALSE;
}
Bool
IsGestureBeginEvent(InternalEvent *event)
{
switch (event->any.type) {
case ET_GesturePinchBegin:
case ET_GestureSwipeBegin:
return TRUE;
default:
break;
}
return FALSE;
}
Bool
IsGestureEndEvent(InternalEvent *event)
{
switch (event->any.type) {
case ET_GesturePinchEnd:
case ET_GestureSwipeEnd:
return TRUE;
default:
break;
}
return FALSE;
}
/**
* @return the device matching the deviceid of the device set in the event, or
* NULL if the event is not an XInput event.
@ -575,8 +619,10 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
memcpy(to->button->xkb_acts, from->button->xkb_acts,
sizeof(XkbAction));
}
else
else {
free(to->button->xkb_acts);
to->button->xkb_acts = NULL;
}
memcpy(to->button->labels, from->button->labels,
from->button->numButtons * sizeof(Atom));
@ -647,6 +693,25 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
/* Don't remove touch class if from->touch is non-existent. The to device
* may have an active touch grab, so we need to keep the touch class record
* around. */
if (from->gesture) {
if (!to->gesture) {
classes = to->unused_classes;
to->gesture = classes->gesture;
if (!to->gesture) {
if (!InitGestureClassDeviceStruct(to, from->gesture->max_touches))
FatalError("[Xi] no memory for class shift.\n");
}
else
classes->gesture = NULL;
}
to->gesture->sourceid = from->gesture->sourceid;
/* to->gesture->gesture is separate on the master, don't copy */
}
/* Don't remove gesture class if from->gesture is non-existent. The to device
* may have an active gesture grab, so we need to keep the gesture class record
* around. */
}
/**
@ -1292,21 +1357,13 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
int rc;
InputClients *iclients = NULL;
*mask = NULL;
*grab = NULL;
if (listener->type == TOUCH_LISTENER_GRAB ||
listener->type == TOUCH_LISTENER_POINTER_GRAB) {
*grab = listener->grab;
BUG_RETURN_VAL(!*grab, FALSE);
}
else if (ti->emulate_pointer && dev->deviceGrab.grab &&
!dev->deviceGrab.fromPassiveGrab) {
/* There may be an active pointer grab on the device */
*grab = dev->deviceGrab.grab;
}
if (*grab) {
*client = rClient(*grab);
*win = (*grab)->window;
*mask = (*grab)->xi2mask;
@ -1363,6 +1420,8 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
/* if owner selected, oclients is NULL */
*client = oclients ? rClient(oclients) : wClient(*win);
}
*grab = NULL;
}
return TRUE;
@ -1379,6 +1438,16 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
int nevents;
DeviceIntPtr kbd;
/* There may be a pointer grab on the device */
if (!grab) {
grab = dev->deviceGrab.grab;
if (grab) {
win = grab->window;
xi2mask = grab->xi2mask;
client = rClient(grab);
}
}
/* We don't deliver pointer events to non-owners */
if (!TouchResourceIsOwner(ti, listener->listener))
return !Success;
@ -1457,7 +1526,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
g = AllocGrab(devgrab);
BUG_WARN(!g);
*dev->deviceGrab.sync.event = *ev;
CopyPartialInternalEvent(dev->deviceGrab.sync.event, ev);
/* The listener array has a sequence of grabs and then one event
* selection. Implicit grab activation occurs through delivering an
@ -1676,6 +1745,72 @@ ProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev)
free(ev);
}
static BOOL
IsAnotherGestureActiveOnMaster(DeviceIntPtr dev, InternalEvent* ev)
{
GestureClassPtr g = dev->gesture;
if (g->gesture.active && g->gesture.sourceid != ev->gesture_event.sourceid) {
return TRUE;
}
return FALSE;
}
/**
* Processes and delivers a Gesture{Pinch,Swipe}{Begin,Update,End}.
*
* Due to having rather different delivery semantics (see the Xi 2.4 protocol
* spec for more information), this implements its own grab and event-selection
* delivery logic.
*/
void
ProcessGestureEvent(InternalEvent *ev, DeviceIntPtr dev)
{
GestureInfoPtr gi;
DeviceIntPtr kbd;
Bool deactivateGestureGrab = FALSE;
Bool delivered = FALSE;
if (!dev->gesture)
return;
if (IsMaster(dev) && IsAnotherGestureActiveOnMaster(dev, ev))
return;
if (IsGestureBeginEvent(ev))
gi = GestureBeginGesture(dev, ev);
else
gi = GestureFindActiveByEventType(dev, ev->any.type);
if (!gi) {
/* This may happen if gesture is no longer active or was never started. */
return;
}
kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
event_set_state_gesture(kbd, &ev->gesture_event);
if (IsGestureBeginEvent(ev))
GestureSetupListener(dev, gi, ev);
if (IsGestureEndEvent(ev) &&
dev->deviceGrab.grab &&
dev->deviceGrab.fromPassiveGrab &&
GrabIsGestureGrab(dev->deviceGrab.grab))
deactivateGestureGrab = TRUE;
delivered = DeliverGestureEventToOwner(dev, gi, ev);
if (delivered && !deactivateGestureGrab &&
(IsGestureBeginEvent(ev) || IsGestureEndEvent(ev)))
FreezeThisEventIfNeededForSyncGrab(dev, ev);
if (IsGestureEndEvent(ev))
GestureEndGesture(gi);
if (deactivateGestureGrab)
(*dev->deviceGrab.DeactivateGrab) (dev);
}
/**
* Process DeviceEvents and DeviceChangedEvents.
*/
@ -1768,7 +1903,7 @@ ProcessDeviceEvent(InternalEvent *ev, DeviceIntPtr device)
* nested) to clients. */
if (event->source_type == EVENT_SOURCE_FOCUS)
return;
if (!grab && CheckDeviceGrabs(device, event, 0))
if (!grab && CheckDeviceGrabs(device, ev, 0))
return;
break;
case ET_KeyRelease:
@ -1781,7 +1916,7 @@ ProcessDeviceEvent(InternalEvent *ev, DeviceIntPtr device)
if (b->map[key] == 0) /* there's no button 0 */
return;
event->detail.button = b->map[key];
if (!grab && CheckDeviceGrabs(device, event, 0)) {
if (!grab && CheckDeviceGrabs(device, ev, 0)) {
/* if a passive grab was activated, the event has been sent
* already */
return;
@ -1870,6 +2005,14 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
case ET_BarrierLeave:
ProcessBarrierEvent(ev, device);
break;
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
ProcessGestureEvent(ev, device);
break;
default:
ProcessDeviceEvent(ev, device);
break;
@ -2074,6 +2217,111 @@ DeliverTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti,
}
}
/**
* Attempts to deliver a gesture event to the given client.
*/
static Bool
DeliverOneGestureEvent(ClientPtr client, DeviceIntPtr dev, GestureInfoPtr gi,
GrabPtr grab, WindowPtr win, InternalEvent *ev)
{
int err;
xEvent *xi2;
Mask filter;
Window child = DeepestSpriteWin(&gi->sprite)->drawable.id;
/* If we fail here, we're going to leave a client hanging. */
err = EventToXI2(ev, &xi2);
if (err != Success)
FatalError("[Xi] %s: XI2 conversion failed in %s"
" (%d)\n", dev->name, __func__, err);
FixUpEventFromWindow(&gi->sprite, xi2, win, child, FALSE);
filter = GetEventFilter(dev, xi2);
if (XaceHook(XACE_RECEIVE_ACCESS, client, win, xi2, 1) != Success)
return FALSE;
err = TryClientEvents(client, dev, xi2, 1, filter, filter, NullGrab);
free(xi2);
/* Returning the value from TryClientEvents isn't useful, since all our
* resource-gone cleanups will update the delivery list anyway. */
return TRUE;
}
/**
* Given a gesture event and a potential listener, retrieve info needed for processing the event.
*
* @param dev The device generating the gesture event.
* @param ev The gesture event to process.
* @param listener The gesture event listener that may receive the gesture event.
* @param[out] client The client that should receive the gesture event.
* @param[out] win The window to deliver the event on.
* @param[out] grab The grab to deliver the event through, if any.
* @return TRUE if an event should be delivered to the listener, FALSE
* otherwise.
*/
static Bool
RetrieveGestureDeliveryData(DeviceIntPtr dev, InternalEvent *ev, GestureListener* listener,
ClientPtr *client, WindowPtr *win, GrabPtr *grab)
{
int rc;
int evtype;
InputClients *iclients = NULL;
*grab = NULL;
if (listener->type == GESTURE_LISTENER_GRAB ||
listener->type == GESTURE_LISTENER_NONGESTURE_GRAB) {
*grab = listener->grab;
BUG_RETURN_VAL(!*grab, FALSE);
*client = rClient(*grab);
*win = (*grab)->window;
}
else {
rc = dixLookupResourceByType((void **) win, listener->listener, listener->resource_type,
serverClient, DixSendAccess);
if (rc != Success)
return FALSE;
/* note that we only will have XI2 listeners as
listener->type == GESTURE_LISTENER_REGULAR */
evtype = GetXI2Type(ev->any.type);
nt_list_for_each_entry(iclients, wOtherInputMasks(*win)->inputClients, next)
if (xi2mask_isset(iclients->xi2mask, dev, evtype))
break;
BUG_RETURN_VAL(!iclients, FALSE);
*client = rClient(iclients);
}
return TRUE;
}
/**
* Delivers a gesture to the owner, if possible and needed. Returns whether
* an event was delivered.
*/
Bool
DeliverGestureEventToOwner(DeviceIntPtr dev, GestureInfoPtr gi, InternalEvent *ev)
{
GrabPtr grab = NULL;
ClientPtr client;
WindowPtr win;
if (!gi->has_listener || gi->listener.type == GESTURE_LISTENER_NONGESTURE_GRAB) {
return 0;
}
if (!RetrieveGestureDeliveryData(dev, ev, &gi->listener, &client, &win, &grab))
return 0;
ev->gesture_event.deviceid = dev->id;
return DeliverOneGestureEvent(client, dev, gi, grab, win, ev);
}
int
InitProximityClassDeviceStruct(DeviceIntPtr dev)
{
@ -2379,8 +2627,8 @@ GrabWindow(ClientPtr client, DeviceIntPtr dev, int type,
/* Touch grab */
int
GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
GrabParameters *param, GrabMask *mask)
GrabTouchOrGesture(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
int type, GrabParameters *param, GrabMask *mask)
{
WindowPtr pWin;
GrabPtr grab;
@ -2398,7 +2646,7 @@ GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
return rc;
grab = CreateGrab(client->index, dev, mod_dev, pWin, XI2,
mask, param, XI_TouchBegin, 0, NullWindow, NullCursor);
mask, param, type, 0, NullWindow, NullCursor);
if (!grab)
return BadAlloc;

View File

@ -850,6 +850,74 @@ SBarrierEvent(xXIBarrierEvent * from,
swapl(&to->eventid);
}
static void
SGesturePinchEvent(xXIGesturePinchEvent* from,
xXIGesturePinchEvent* to)
{
*to = *from;
swaps(&to->sequenceNumber);
swapl(&to->length);
swaps(&to->evtype);
swaps(&to->deviceid);
swapl(&to->time);
swapl(&to->detail);
swapl(&to->root);
swapl(&to->event);
swapl(&to->child);
swapl(&to->root_x);
swapl(&to->root_y);
swapl(&to->event_x);
swapl(&to->event_y);
swapl(&to->delta_x);
swapl(&to->delta_y);
swapl(&to->delta_unaccel_x);
swapl(&to->delta_unaccel_y);
swapl(&to->scale);
swapl(&to->delta_angle);
swaps(&to->sourceid);
swapl(&to->mods.base_mods);
swapl(&to->mods.latched_mods);
swapl(&to->mods.locked_mods);
swapl(&to->mods.effective_mods);
swapl(&to->flags);
}
static void
SGestureSwipeEvent(xXIGestureSwipeEvent* from,
xXIGestureSwipeEvent* to)
{
*to = *from;
swaps(&to->sequenceNumber);
swapl(&to->length);
swaps(&to->evtype);
swaps(&to->deviceid);
swapl(&to->time);
swapl(&to->detail);
swapl(&to->root);
swapl(&to->event);
swapl(&to->child);
swapl(&to->root_x);
swapl(&to->root_y);
swapl(&to->event_x);
swapl(&to->event_y);
swapl(&to->delta_x);
swapl(&to->delta_y);
swapl(&to->delta_unaccel_x);
swapl(&to->delta_unaccel_y);
swaps(&to->sourceid);
swapl(&to->mods.base_mods);
swapl(&to->mods.latched_mods);
swapl(&to->mods.locked_mods);
swapl(&to->mods.effective_mods);
swapl(&to->flags);
}
/** Event swapping function for XI2 events. */
void _X_COLD
XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
@ -901,6 +969,18 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
SBarrierEvent((xXIBarrierEvent *) from,
(xXIBarrierEvent *) to);
break;
case XI_GesturePinchBegin:
case XI_GesturePinchUpdate:
case XI_GesturePinchEnd:
SGesturePinchEvent((xXIGesturePinchEvent*) from,
(xXIGesturePinchEvent*) to);
break;
case XI_GestureSwipeBegin:
case XI_GestureSwipeUpdate:
case XI_GestureSwipeEnd:
SGestureSwipeEvent((xXIGestureSwipeEvent*) from,
(xXIGestureSwipeEvent*) to);
break;
default:
ErrorF("[Xi] Unknown event type to swap. This is a bug.\n");
break;

View File

@ -39,6 +39,6 @@
int SProcXIChangeHierarchy(ClientPtr /* client */ );
int ProcXIChangeHierarchy(ClientPtr /* client */ );
void XISendDeviceHierarchyEvent(int flags[]);
void XISendDeviceHierarchyEvent(int flags[MAXDEVICES]);
#endif /* CHDEVHIER_H */

View File

@ -114,14 +114,18 @@ ProcXIPassiveGrabDevice(ClientPtr client)
stuff->grab_type != XIGrabtypeKeycode &&
stuff->grab_type != XIGrabtypeEnter &&
stuff->grab_type != XIGrabtypeFocusIn &&
stuff->grab_type != XIGrabtypeTouchBegin) {
stuff->grab_type != XIGrabtypeTouchBegin &&
stuff->grab_type != XIGrabtypeGesturePinchBegin &&
stuff->grab_type != XIGrabtypeGestureSwipeBegin) {
client->errorValue = stuff->grab_type;
return BadValue;
}
if ((stuff->grab_type == XIGrabtypeEnter ||
stuff->grab_type == XIGrabtypeFocusIn ||
stuff->grab_type == XIGrabtypeTouchBegin) && stuff->detail != 0) {
stuff->grab_type == XIGrabtypeTouchBegin ||
stuff->grab_type == XIGrabtypeGesturePinchBegin ||
stuff->grab_type == XIGrabtypeGestureSwipeBegin) && stuff->detail != 0) {
client->errorValue = stuff->detail;
return BadValue;
}
@ -133,6 +137,12 @@ ProcXIPassiveGrabDevice(ClientPtr client)
return BadValue;
}
/* XI2 allows 32-bit keycodes but thanks to XKB we can never
* implement this. Just return an error for all keycodes that
* cannot work anyway, same for buttons > 255. */
if (stuff->detail > 255)
return XIAlreadyGrabbed;
if (XICheckInvalidMaskBits(client, (unsigned char *) &stuff[1],
stuff->mask_len * 4) != Success)
return BadValue;
@ -203,21 +213,24 @@ ProcXIPassiveGrabDevice(ClientPtr client)
&param, XI2, &mask);
break;
case XIGrabtypeKeycode:
/* XI2 allows 32-bit keycodes but thanks to XKB we can never
* implement this. Just return an error for all keycodes that
* cannot work anyway */
if (stuff->detail > 255)
status = XIAlreadyGrabbed;
else
status = GrabKey(client, dev, mod_dev, stuff->detail,
&param, XI2, &mask);
status = GrabKey(client, dev, mod_dev, stuff->detail,
&param, XI2, &mask);
break;
case XIGrabtypeEnter:
case XIGrabtypeFocusIn:
status = GrabWindow(client, dev, stuff->grab_type, &param, &mask);
break;
case XIGrabtypeTouchBegin:
status = GrabTouch(client, dev, mod_dev, &param, &mask);
status = GrabTouchOrGesture(client, dev, mod_dev, XI_TouchBegin,
&param, &mask);
break;
case XIGrabtypeGesturePinchBegin:
status = GrabTouchOrGesture(client, dev, mod_dev,
XI_GesturePinchBegin, &param, &mask);
break;
case XIGrabtypeGestureSwipeBegin:
status = GrabTouchOrGesture(client, dev, mod_dev,
XI_GestureSwipeBegin, &param, &mask);
break;
}
@ -307,7 +320,9 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
stuff->grab_type != XIGrabtypeKeycode &&
stuff->grab_type != XIGrabtypeEnter &&
stuff->grab_type != XIGrabtypeFocusIn &&
stuff->grab_type != XIGrabtypeTouchBegin) {
stuff->grab_type != XIGrabtypeTouchBegin &&
stuff->grab_type != XIGrabtypeGesturePinchBegin &&
stuff->grab_type != XIGrabtypeGestureSwipeBegin) {
client->errorValue = stuff->grab_type;
return BadValue;
}
@ -319,6 +334,12 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
return BadValue;
}
/* We don't allow passive grabs for details > 255 anyway */
if (stuff->detail > 255) {
client->errorValue = stuff->detail;
return BadValue;
}
rc = dixLookupWindow(&win, stuff->grab_window, client, DixSetAttrAccess);
if (rc != Success)
return rc;
@ -348,6 +369,12 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
case XIGrabtypeTouchBegin:
tempGrab->type = XI_TouchBegin;
break;
case XIGrabtypeGesturePinchBegin:
tempGrab->type = XI_GesturePinchBegin;
break;
case XIGrabtypeGestureSwipeBegin:
tempGrab->type = XI_GestureSwipeBegin;
break;
}
tempGrab->grabtype = XI2;
tempGrab->modifierDevice = mod_dev;

View File

@ -890,7 +890,7 @@ ProcXChangeDeviceProperty(ClientPtr client)
REQUEST(xChangeDevicePropertyReq);
DeviceIntPtr dev;
unsigned long len;
int totalSize;
uint64_t totalSize;
int rc;
REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq);
@ -902,6 +902,8 @@ ProcXChangeDeviceProperty(ClientPtr client)
rc = check_change_property(client, stuff->property, stuff->type,
stuff->format, stuff->mode, stuff->nUnits);
if (rc != Success)
return rc;
len = stuff->nUnits;
if (len > (bytes_to_int32(0xffffffff - sizeof(xChangeDevicePropertyReq))))
@ -1128,7 +1130,7 @@ ProcXIChangeProperty(ClientPtr client)
{
int rc;
DeviceIntPtr dev;
int totalSize;
uint64_t totalSize;
unsigned long len;
REQUEST(xXIChangePropertyReq);
@ -1141,6 +1143,9 @@ ProcXIChangeProperty(ClientPtr client)
rc = check_change_property(client, stuff->property, stuff->type,
stuff->format, stuff->mode, stuff->num_items);
if (rc != Success)
return rc;
len = stuff->num_items;
if (len > bytes_to_int32(0xffffffff - sizeof(xXIChangePropertyReq)))
return BadLength;

View File

@ -43,6 +43,9 @@
#include "xace.h"
#include "inpututils.h"
#include "exglobals.h"
#include "privates.h"
#include "xiquerydevice.h"
static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d);
@ -234,6 +237,9 @@ SizeDeviceClasses(DeviceIntPtr dev)
if (dev->touch)
len += sizeof(xXITouchInfo);
if (dev->gesture)
len += sizeof(xXIGestureInfo);
return len;
}
@ -464,6 +470,46 @@ SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
swaps(&touch->sourceid);
}
static Bool ShouldListGestureInfo(ClientPtr client)
{
/* libxcb 14.1 and older are not forwards-compatible with new device classes as it does not
* properly ignore unknown device classes. Since breaking libxcb would break quite a lot of
* applications, we instead report Gesture device class only if the client advertised support
* for XI 2.4. Clients may still not work in cases when a client advertises XI 2.4 support
* and then a completely separate module within the client uses broken libxcb to call
* XIQueryDevice.
*/
XIClientPtr pXIClient = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey);
if (pXIClient->major_version) {
return version_compare(pXIClient->major_version, pXIClient->minor_version, 2, 4) >= 0;
}
return FALSE;
}
/**
* List gesture information
*
* @return The number of bytes written into info.
*/
static int
ListGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
{
gesture->type = XIGestureClass;
gesture->length = sizeof(xXIGestureInfo) >> 2;
gesture->sourceid = dev->gesture->sourceid;
gesture->num_touches = dev->gesture->max_touches;
return gesture->length << 2;
}
static void
SwapGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
{
swaps(&gesture->type);
swaps(&gesture->length);
swaps(&gesture->sourceid);
}
int
GetDeviceUse(DeviceIntPtr dev, uint16_t * attachment)
{
@ -567,6 +613,13 @@ ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
total_len += len;
}
if (dev->gesture && ShouldListGestureInfo(client)) {
(*nclasses)++;
len = ListGestureInfo(dev, (xXIGestureInfo *) any);
any += len;
total_len += len;
}
return total_len;
}
@ -598,7 +651,9 @@ SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info)
case XITouchClass:
SwapTouchInfo(dev, (xXITouchInfo *) any);
break;
case XIGestureClass:
SwapGestureInfo(dev, (xXIGestureInfo *) any);
break;
}
any += len * 4;

View File

@ -226,8 +226,41 @@ ProcXISelectEvents(ClientPtr client)
return BadValue;
}
/* Only one client per window may select for touch events on the
* same devices, including master devices.
/* All three pinch gesture events must be selected at once */
if ((BitIsOn(bits, XI_GesturePinchBegin) ||
BitIsOn(bits, XI_GesturePinchUpdate) ||
BitIsOn(bits, XI_GesturePinchEnd)) &&
(!BitIsOn(bits, XI_GesturePinchBegin) ||
!BitIsOn(bits, XI_GesturePinchUpdate) ||
!BitIsOn(bits, XI_GesturePinchEnd))) {
client->errorValue = XI_GesturePinchBegin;
return BadValue;
}
/* All three swipe gesture events must be selected at once. Note
that the XI_GestureSwipeEnd is at index 32 which is on the next
4-byte mask element */
if (evmask->mask_len == 1 &&
(BitIsOn(bits, XI_GestureSwipeBegin) ||
BitIsOn(bits, XI_GestureSwipeUpdate)))
{
client->errorValue = XI_GestureSwipeBegin;
return BadValue;
}
if (evmask->mask_len >= 2 &&
(BitIsOn(bits, XI_GestureSwipeBegin) ||
BitIsOn(bits, XI_GestureSwipeUpdate) ||
BitIsOn(bits, XI_GestureSwipeEnd)) &&
(!BitIsOn(bits, XI_GestureSwipeBegin) ||
!BitIsOn(bits, XI_GestureSwipeUpdate) ||
!BitIsOn(bits, XI_GestureSwipeEnd))) {
client->errorValue = XI_GestureSwipeBegin;
return BadValue;
}
/* Only one client per window may select for touch or gesture events
* on the same devices, including master devices.
* XXX: This breaks if a device goes from floating to attached. */
if (BitIsOn(bits, XI_TouchBegin)) {
rc = check_for_touch_selection_conflicts(client,
@ -237,6 +270,22 @@ ProcXISelectEvents(ClientPtr client)
if (rc != Success)
return rc;
}
if (BitIsOn(bits, XI_GesturePinchBegin)) {
rc = check_for_touch_selection_conflicts(client,
win,
evmask->deviceid,
XI_GesturePinchBegin);
if (rc != Success)
return rc;
}
if (BitIsOn(bits, XI_GestureSwipeBegin)) {
rc = check_for_touch_selection_conflicts(client,
win,
evmask->deviceid,
XI_GestureSwipeBegin);
if (rc != Success)
return rc;
}
}
if (XICheckInvalidMaskBits(client, (unsigned char *) &evmask[1],

View File

@ -561,7 +561,11 @@ static int _X_COLD
SProcDamageDispatch(ClientPtr client)
{
REQUEST(xDamageReq);
if (stuff->damageReqType >= XDamageNumberRequests)
DamageClientPtr pDamageClient = GetDamageClient(client);
if (pDamageClient->major_version >= ARRAY_SIZE(version_requests))
return BadRequest;
if (stuff->damageReqType > version_requests[pDamageClient->major_version])
return BadRequest;
return (*SProcDamageVector[stuff->damageReqType]) (client);
}

View File

@ -1,57 +0,0 @@
#
# Generate output formats for a single DocBook/XML with/without chapters
#
# Variables set by the calling Makefile:
# noinst_DATA: developers docs are not installed
# docbook: the main DocBook/XML file, no chapters, appendix or image files
# chapters: all files pulled in by an XInclude statement and images.
#
#
# This makefile is intended for Developers Documentation and is not installed.
# Do not use for Users docs or Specs which need to be installed and require olink support
# Refer to http://www.x.org/releases/X11R7.6/doc/xorg-docs/ReleaseNotes.html#id2584393
# for an explanation on documents classification.
#
# Developers documnetation is not installed
noinst_DATA =
# DocBook/XML file with chapters, appendix and images it includes
dist_noinst_DATA = $(docbook) $(chapters)
FILTER_XMLTO=$(SHELL) $(top_srcdir)/doc/filter-xmlto.sh $(XMLTO)
if HAVE_STYLESHEETS
XMLTO_HTML_FLAGS = \
--searchpath "$(XORG_SGML_PATH)/X11" \
--searchpath "$(abs_top_builddir)" \
-x $(STYLESHEET_SRCDIR)/xorg-xhtml.xsl
noinst_DATA += $(docbook:.xml=.html)
%.html: %.xml $(chapters)
$(AM_V_GEN)$(FILTER_XMLTO) $(XMLTO_HTML_FLAGS) xhtml-nochunks $<
if HAVE_XMLTO_TEXT
noinst_DATA += $(docbook:.xml=.txt)
%.txt: %.xml $(chapters)
$(AM_V_GEN)$(FILTER_XMLTO) $(XMLTO_HTML_FLAGS) txt $<
endif HAVE_XMLTO_TEXT
if HAVE_FOP
XMLTO_FO_FLAGS = \
--searchpath "$(XORG_SGML_PATH)/X11" \
--searchpath "$(abs_top_builddir)" \
--stringparam img.src.path=$(abs_builddir)/ \
-x $(STYLESHEET_SRCDIR)/xorg-fo.xsl
noinst_DATA += $(docbook:.xml=.pdf) $(docbook:.xml=.ps)
%.pdf: %.xml $(chapters)
$(AM_V_GEN)$(FILTER_XMLTO) $(XMLTO_FO_FLAGS) --with-fop pdf $<
%.ps: %.xml $(chapters)
$(AM_V_GEN)$(FILTER_XMLTO) $(XMLTO_FO_FLAGS) --with-fop ps $<
endif HAVE_FOP
endif HAVE_STYLESHEETS
CLEANFILES = $(noinst_DATA)

View File

@ -458,6 +458,7 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent)
return FALSE;
TouchEndPhysicallyActiveTouches(dev);
GestureEndActiveGestures(dev);
ReleaseButtonsAndKeys(dev);
SyncRemoveDeviceIdleTime(dev->idle_counter);
dev->idle_counter = NULL;
@ -1670,6 +1671,32 @@ InitTouchClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches,
return FALSE;
}
/**
* Sets up gesture capabilities on @device.
*
* @max_touches The maximum number of simultaneous touches, or 0 for unlimited.
*/
Bool
InitGestureClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches)
{
GestureClassPtr g;
BUG_RETURN_VAL(device == NULL, FALSE);
BUG_RETURN_VAL(device->gesture != NULL, FALSE);
g = calloc(1, sizeof(*g));
if (!g)
return FALSE;
g->sourceid = device->id;
g->max_touches = max_touches;
GestureInitGestureInfo(&g->gesture);
device->gesture = g;
return TRUE;
}
/*
* Check if the given buffer contains elements between low (inclusive) and
* high (inclusive) only.

View File

@ -128,6 +128,7 @@ int ProcInitialConnection();
#include "inputstr.h"
#include "xkbsrv.h"
#include "client.h"
#include "xfixesint.h"
#ifdef XSERVER_DTRACE
#include "registry.h"
@ -164,6 +165,7 @@ static int nextFreeClientID; /* always MIN free client ID */
static int nClients; /* number of authorized clients */
CallbackListPtr ClientStateCallback;
OsTimerPtr dispatchExceptionTimer;
/* dispatchException & isItTimeToYield must be declared volatile since they
* are modified by signal handlers - otherwise optimizer may assume it doesn't
@ -399,6 +401,58 @@ SmartScheduleClient(void)
return best;
}
static CARD32
DispatchExceptionCallback(OsTimerPtr timer, CARD32 time, void *arg)
{
dispatchException |= dispatchExceptionAtReset;
/* Don't re-arm the timer */
return 0;
}
static void
CancelDispatchExceptionTimer(void)
{
TimerFree(dispatchExceptionTimer);
dispatchExceptionTimer = NULL;
}
static void
SetDispatchExceptionTimer(void)
{
/* The timer delay is only for terminate, not reset */
if (!(dispatchExceptionAtReset & DE_TERMINATE)) {
dispatchException |= dispatchExceptionAtReset;
return;
}
CancelDispatchExceptionTimer();
if (terminateDelay == 0)
dispatchException |= dispatchExceptionAtReset;
else
dispatchExceptionTimer = TimerSet(dispatchExceptionTimer,
0, terminateDelay * 1000 /* msec */,
&DispatchExceptionCallback,
NULL);
}
static Bool
ShouldDisconnectRemainingClients(void)
{
int i;
for (i = 1; i < currentMaxClients; i++) {
if (clients[i]) {
if (!XFixesShouldDisconnectClient(clients[i]))
return FALSE;
}
}
/* All remaining clients can be safely ignored */
return TRUE;
}
void
EnableLimitedSchedulingLatency(void)
{
@ -3419,6 +3473,7 @@ ProcNoOperation(ClientPtr client)
*********************/
char dispatchExceptionAtReset = DE_RESET;
int terminateDelay = 0;
void
CloseDownClient(ClientPtr client)
@ -3475,7 +3530,7 @@ CloseDownClient(ClientPtr client)
if (really_close_down) {
if (client->clientState == ClientStateRunning && nClients == 0)
dispatchException |= dispatchExceptionAtReset;
SetDispatchExceptionTimer();
client->clientState = ClientStateGone;
if (ClientStateCallback) {
@ -3487,6 +3542,7 @@ CloseDownClient(ClientPtr client)
CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
}
TouchListenerGone(client->clientAsMask);
GestureListenerGone(client->clientAsMask);
FreeClientResources(client);
/* Disable client ID tracking. This must be done after
* ClientStateCallback. */
@ -3503,6 +3559,9 @@ CloseDownClient(ClientPtr client)
while (!clients[currentMaxClients - 1])
currentMaxClients--;
}
if (ShouldDisconnectRemainingClients())
SetDispatchExceptionTimer();
}
static void
@ -3704,6 +3763,7 @@ SendConnSetup(ClientPtr client, const char *reason)
clientinfo.setup = (xConnSetup *) lConnectionInfo;
CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
}
CancelDispatchExceptionTimer();
return Success;
}

View File

@ -56,7 +56,7 @@
*
* For a full description of the focus in/out model from a window's
* perspective, see
* http://lists.freedesktop.org/archives/xorg/2008-December/041740.html
* https://lists.freedesktop.org/archives/xorg/2008-December/041684.html
*
* Additional notes:
* - The core protocol spec says that "In a LeaveNotify event, if a child of the

View File

@ -59,6 +59,8 @@ static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
static int eventToBarrierEvent(BarrierEvent *ev, xEvent **xi);
static int eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi);
static int eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi);
static int eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi);
/* Do not use, read comments below */
BOOL EventIsKeyRepeat(xEvent *event);
@ -163,6 +165,12 @@ EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
case ET_TouchOwnership:
case ET_BarrierHit:
case ET_BarrierLeave:
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
ret = BadMatch;
break;
default:
@ -221,6 +229,12 @@ EventToXI(InternalEvent *ev, xEvent **xi, int *count)
case ET_TouchOwnership:
case ET_BarrierHit:
case ET_BarrierLeave:
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
*count = 0;
*xi = NULL;
return BadMatch;
@ -285,6 +299,14 @@ EventToXI2(InternalEvent *ev, xEvent **xi)
case ET_BarrierHit:
case ET_BarrierLeave:
return eventToBarrierEvent(&ev->barrier_event, xi);
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return eventToGesturePinchEvent(&ev->gesture_event, xi);
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return eventToGestureSwipeEvent(&ev->gesture_event, xi);
default:
break;
}
@ -816,6 +838,88 @@ eventToBarrierEvent(BarrierEvent *ev, xEvent **xi)
return Success;
}
int
eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi)
{
int len = sizeof(xXIGesturePinchEvent);
xXIGesturePinchEvent *xpe;
*xi = calloc(1, len);
xpe = (xXIGesturePinchEvent *) * xi;
xpe->type = GenericEvent;
xpe->extension = IReqCode;
xpe->evtype = GetXI2Type(ev->type);
xpe->time = ev->time;
xpe->length = bytes_to_int32(len - sizeof(xEvent));
xpe->detail = ev->num_touches;
xpe->root = ev->root;
xpe->deviceid = ev->deviceid;
xpe->sourceid = ev->sourceid;
xpe->root_x = double_to_fp1616(ev->root_x);
xpe->root_y = double_to_fp1616(ev->root_y);
xpe->flags |= (ev->flags & GESTURE_CANCELLED) ? XIGesturePinchEventCancelled : 0;
xpe->delta_x = double_to_fp1616(ev->delta_x);
xpe->delta_y = double_to_fp1616(ev->delta_y);
xpe->delta_unaccel_x = double_to_fp1616(ev->delta_unaccel_x);
xpe->delta_unaccel_y = double_to_fp1616(ev->delta_unaccel_y);
xpe->scale = double_to_fp1616(ev->scale);
xpe->delta_angle = double_to_fp1616(ev->delta_angle);
xpe->mods.base_mods = ev->mods.base;
xpe->mods.latched_mods = ev->mods.latched;
xpe->mods.locked_mods = ev->mods.locked;
xpe->mods.effective_mods = ev->mods.effective;
xpe->group.base_group = ev->group.base;
xpe->group.latched_group = ev->group.latched;
xpe->group.locked_group = ev->group.locked;
xpe->group.effective_group = ev->group.effective;
return Success;
}
int
eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi)
{
int len = sizeof(xXIGestureSwipeEvent);
xXIGestureSwipeEvent *xde;
*xi = calloc(1, len);
xde = (xXIGestureSwipeEvent *) * xi;
xde->type = GenericEvent;
xde->extension = IReqCode;
xde->evtype = GetXI2Type(ev->type);
xde->time = ev->time;
xde->length = bytes_to_int32(len - sizeof(xEvent));
xde->detail = ev->num_touches;
xde->root = ev->root;
xde->deviceid = ev->deviceid;
xde->sourceid = ev->sourceid;
xde->root_x = double_to_fp1616(ev->root_x);
xde->root_y = double_to_fp1616(ev->root_y);
xde->flags |= (ev->flags & GESTURE_CANCELLED) ? XIGestureSwipeEventCancelled : 0;
xde->delta_x = double_to_fp1616(ev->delta_x);
xde->delta_y = double_to_fp1616(ev->delta_y);
xde->delta_unaccel_x = double_to_fp1616(ev->delta_unaccel_x);
xde->delta_unaccel_y = double_to_fp1616(ev->delta_unaccel_y);
xde->mods.base_mods = ev->mods.base;
xde->mods.latched_mods = ev->mods.latched;
xde->mods.locked_mods = ev->mods.locked;
xde->mods.effective_mods = ev->mods.effective;
xde->group.base_group = ev->group.base;
xde->group.latched_group = ev->group.latched;
xde->group.locked_group = ev->group.locked;
xde->group.effective_group = ev->group.effective;
return Success;
}
/**
* Return the corresponding core type for the given event or 0 if no core
* equivalent exists.
@ -969,8 +1073,68 @@ GetXI2Type(enum EventType type)
case ET_BarrierLeave:
xi2type = XI_BarrierLeave;
break;
case ET_GesturePinchBegin:
xi2type = XI_GesturePinchBegin;
break;
case ET_GesturePinchUpdate:
xi2type = XI_GesturePinchUpdate;
break;
case ET_GesturePinchEnd:
xi2type = XI_GesturePinchEnd;
break;
case ET_GestureSwipeBegin:
xi2type = XI_GestureSwipeBegin;
break;
case ET_GestureSwipeUpdate:
xi2type = XI_GestureSwipeUpdate;
break;
case ET_GestureSwipeEnd:
xi2type = XI_GestureSwipeEnd;
break;
default:
break;
}
return xi2type;
}
/**
* Converts a gesture type to corresponding Gesture{Pinch,Swipe}Begin.
* Returns 0 if the input type is not a gesture.
*/
enum EventType
GestureTypeToBegin(enum EventType type)
{
switch (type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return ET_GesturePinchBegin;
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return ET_GestureSwipeBegin;
default:
return 0;
}
}
/**
* Converts a gesture type to corresponding Gesture{Pinch,Swipe}End.
* Returns 0 if the input type is not a gesture.
*/
enum EventType
GestureTypeToEnd(enum EventType type)
{
switch (type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return ET_GesturePinchEnd;
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return ET_GestureSwipeEnd;
default:
return 0;
}
}

View File

@ -467,6 +467,20 @@ WindowXI2MaskIsset(DeviceIntPtr dev, WindowPtr win, xEvent *ev)
return xi2mask_isset(inputMasks->xi2mask, dev, evtype);
}
/**
* When processing events we operate on InternalEvent pointers. They may actually refer to a
* an instance of DeviceEvent, GestureEvent or any other event that comprises the InternalEvent
* union. This works well in practice because we always look into event type before doing anything,
* except in the case of copying the event. Any copying of InternalEvent should use this function
* instead of doing *dst_event = *src_event whenever it's not clear whether source event actually
* points to full InternalEvent instance.
*/
void
CopyPartialInternalEvent(InternalEvent* dst_event, const InternalEvent* src_event)
{
memcpy(dst_event, src_event, src_event->any.length);
}
Mask
GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients * other)
{
@ -1191,7 +1205,7 @@ EnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
}
}
eventlen = event->length;
eventlen = sizeof(InternalEvent);
qe = malloc(sizeof(QdEventRec) + eventlen);
if (!qe)
@ -1201,7 +1215,7 @@ EnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
qe->pScreen = pSprite->hotPhys.pScreen;
qe->months = currentTime.months;
qe->event = (InternalEvent *) (qe + 1);
memcpy(qe->event, event, eventlen);
CopyPartialInternalEvent(qe->event, (InternalEvent *)event);
xorg_list_append(&qe->next, &syncEvents.pending);
}
@ -1319,7 +1333,7 @@ ComputeFreezes(void)
syncEvents.replayDev = (DeviceIntPtr) NULL;
if (!CheckDeviceGrabs(replayDev, &event->device_event,
if (!CheckDeviceGrabs(replayDev, event,
syncEvents.replayWin)) {
if (IsTouchEvent(event)) {
TouchPointInfoPtr ti =
@ -1328,6 +1342,15 @@ ComputeFreezes(void)
TouchListenerAcceptReject(replayDev, ti, 0, XIRejectTouch);
}
else if (IsGestureEvent(event)) {
GestureInfoPtr gi =
GestureFindActiveByEventType(replayDev, event->any.type);
if (gi) {
GestureEmitGestureEndToOwner(replayDev, gi);
GestureEndGesture(gi);
}
ProcessGestureEvent(event, replayDev);
}
else {
WindowPtr w = XYToWindow(replayDev->spriteInfo->sprite,
event->device_event.root_x,
@ -1480,16 +1503,28 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
if (ti->active &&
CLIENT_BITS(listener->listener) == grab->resource) {
if (grab->grabtype == CORE || grab->grabtype == XI ||
!xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin)) {
if (listener->type == TOUCH_LISTENER_REGULAR &&
listener->state != TOUCH_LISTENER_AWAITING_BEGIN &&
listener->state != TOUCH_LISTENER_HAS_END) {
/* if the listener already got any events relating to the touch, we must send
a touch end because the grab overrides the previous listener and won't
itself send any touch events.
*/
TouchEmitTouchEnd(mouse, ti, 0, listener->listener);
}
listener->type = TOUCH_LISTENER_POINTER_GRAB;
} else {
listener->type = TOUCH_LISTENER_GRAB;
}
listener->listener = grab->resource;
listener->level = grab->grabtype;
listener->state = TOUCH_LISTENER_IS_OWNER;
listener->window = grab->window;
listener->state = TOUCH_LISTENER_IS_OWNER;
if (grab->grabtype == CORE || grab->grabtype == XI ||
!xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin))
listener->type = TOUCH_LISTENER_POINTER_GRAB;
else
listener->type = TOUCH_LISTENER_GRAB;
if (listener->grab)
FreeGrab(listener->grab);
listener->grab = AllocGrab(grab);
@ -1497,6 +1532,46 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
}
}
/**
* Update gesture records when an explicit grab is activated. Any gestures owned
* by the grabbing client are updated so the listener state reflects the new
* grab.
*/
static void
UpdateGesturesForGrab(DeviceIntPtr mouse)
{
if (!mouse->gesture || mouse->deviceGrab.fromPassiveGrab)
return;
GestureInfoPtr gi = &mouse->gesture->gesture;
GestureListener *listener = &gi->listener;
GrabPtr grab = mouse->deviceGrab.grab;
if (gi->active && CLIENT_BITS(listener->listener) == grab->resource) {
if (grab->grabtype == CORE || grab->grabtype == XI ||
!xi2mask_isset(grab->xi2mask, mouse, GetXI2Type(gi->type))) {
if (listener->type == GESTURE_LISTENER_REGULAR) {
/* if the listener already got any events relating to the gesture, we must send
a gesture end because the grab overrides the previous listener and won't
itself send any gesture events.
*/
GestureEmitGestureEndToOwner(mouse, gi);
}
listener->type = GESTURE_LISTENER_NONGESTURE_GRAB;
} else {
listener->type = GESTURE_LISTENER_GRAB;
}
listener->listener = grab->resource;
listener->window = grab->window;
if (listener->grab)
FreeGrab(listener->grab);
listener->grab = AllocGrab(grab);
}
}
/**
* Activate a pointer grab on the given device. A pointer grab will cause all
* core pointer events of this device to be delivered to the grabbing client only.
@ -1547,6 +1622,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
PostNewCursor(mouse);
UpdateTouchesForGrab(mouse);
UpdateGesturesForGrab(mouse);
CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
(Bool) grab->keyboardMode);
if (oldgrab)
@ -1602,6 +1678,16 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
if (dev->deviceGrab.sync.other == grab)
dev->deviceGrab.sync.other = NullGrab;
}
/* in case of explicit gesture grab, send end event to the grab client */
if (!wasPassive && mouse->gesture) {
GestureInfoPtr gi = &mouse->gesture->gesture;
if (gi->active && GestureResourceIsOwner(gi, grab_resource)) {
GestureEmitGestureEndToOwner(mouse, gi);
GestureEndGesture(gi);
}
}
DoEnterLeaveEvents(mouse, mouse->id, grab->window,
mouse->spriteInfo->sprite->win, NotifyUngrab);
if (grab->confineTo)
@ -2533,6 +2619,44 @@ FixUpXI2DeviceEventFromWindow(SpritePtr pSprite, int evtype,
(pSprite->hot.pScreen == pWin->drawable.pScreen);
}
static void
FixUpXI2PinchEventFromWindow(SpritePtr pSprite, xXIGesturePinchEvent *event,
WindowPtr pWin, Window child)
{
event->root = RootWindow(pSprite)->drawable.id;
event->event = pWin->drawable.id;
if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
event->event_x = event->root_x - double_to_fp1616(pWin->drawable.x);
event->event_y = event->root_y - double_to_fp1616(pWin->drawable.y);
event->child = child;
}
else {
event->event_x = 0;
event->event_y = 0;
event->child = None;
}
}
static void
FixUpXI2SwipeEventFromWindow(SpritePtr pSprite, xXIGestureSwipeEvent *event,
WindowPtr pWin, Window child)
{
event->root = RootWindow(pSprite)->drawable.id;
event->event = pWin->drawable.id;
if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
event->event_x = event->root_x - double_to_fp1616(pWin->drawable.x);
event->event_y = event->root_y - double_to_fp1616(pWin->drawable.y);
event->child = child;
}
else {
event->event_x = 0;
event->event_y = 0;
event->child = None;
}
}
/**
* Adjust event fields to comply with the window properties.
*
@ -2566,6 +2690,18 @@ FixUpEventFromWindow(SpritePtr pSprite,
case XI_BarrierHit:
case XI_BarrierLeave:
return;
case XI_GesturePinchBegin:
case XI_GesturePinchUpdate:
case XI_GesturePinchEnd:
FixUpXI2PinchEventFromWindow(pSprite,
(xXIGesturePinchEvent*) xE, pWin, child);
break;
case XI_GestureSwipeBegin:
case XI_GestureSwipeUpdate:
case XI_GestureSwipeEnd:
FixUpXI2SwipeEventFromWindow(pSprite,
(xXIGestureSwipeEvent*) xE, pWin, child);
break;
default:
FixUpXI2DeviceEventFromWindow(pSprite, evtype,
(xXIDeviceEvent*) xE, pWin, child);
@ -2905,7 +3041,7 @@ BOOL
ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win)
{
BOOL rc = FALSE;
DeviceEvent event;
InternalEvent event;
if (dev->deviceGrab.grab) {
if (!dev->deviceGrab.fromPassiveGrab ||
@ -2920,16 +3056,16 @@ ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win)
if (win == NoneWin || win == PointerRootWin)
return FALSE;
event = (DeviceEvent) {
.header = ET_Internal,
.type = ET_FocusIn,
.length = sizeof(DeviceEvent),
.time = GetTimeInMillis(),
.deviceid = dev->id,
.sourceid = dev->id,
.detail.button = 0
event = (InternalEvent) {
.device_event.header = ET_Internal,
.device_event.type = ET_FocusIn,
.device_event.length = sizeof(DeviceEvent),
.device_event.time = GetTimeInMillis(),
.device_event.deviceid = dev->id,
.device_event.sourceid = dev->id,
.device_event.detail.button = 0
};
rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE,
rc = (CheckPassiveGrabsOnWindow(win, dev, &event, FALSE,
TRUE) != NULL);
if (rc)
DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab);
@ -2946,7 +3082,7 @@ static BOOL
ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win)
{
BOOL rc = FALSE;
DeviceEvent event;
InternalEvent event;
if (dev->deviceGrab.grab) {
if (!dev->deviceGrab.fromPassiveGrab ||
@ -2958,16 +3094,16 @@ ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win)
(*dev->deviceGrab.DeactivateGrab) (dev);
}
event = (DeviceEvent) {
.header = ET_Internal,
.type = ET_Enter,
.length = sizeof(DeviceEvent),
.time = GetTimeInMillis(),
.deviceid = dev->id,
.sourceid = dev->id,
.detail.button = 0
event = (InternalEvent) {
.device_event.header = ET_Internal,
.device_event.type = ET_Enter,
.device_event.length = sizeof(DeviceEvent),
.device_event.time = GetTimeInMillis(),
.device_event.deviceid = dev->id,
.device_event.sourceid = dev->id,
.device_event.detail.button = 0
};
rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE,
rc = (CheckPassiveGrabsOnWindow(win, dev, &event, FALSE,
TRUE) != NULL);
if (rc)
DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab);
@ -3751,7 +3887,7 @@ void ActivateGrabNoDelivery(DeviceIntPtr dev, GrabPtr grab,
if (grabinfo->sync.state == FROZEN_NO_EVENT)
grabinfo->sync.state = FROZEN_WITH_EVENT;
*grabinfo->sync.event = *real_event;
CopyPartialInternalEvent(grabinfo->sync.event, real_event);
}
static BOOL
@ -4019,14 +4155,15 @@ CheckPassiveGrabsOnWindow(WindowPtr pWin,
*/
Bool
CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor)
CheckDeviceGrabs(DeviceIntPtr device, InternalEvent *ievent, WindowPtr ancestor)
{
int i;
WindowPtr pWin = NULL;
FocusClassPtr focus =
IsPointerEvent((InternalEvent *) event) ? NULL : device->focus;
IsPointerEvent(ievent) ? NULL : device->focus;
BOOL sendCore = (IsMaster(device) && device->coreEvents);
Bool ret = FALSE;
DeviceEvent *event = &ievent->device_event;
if (event->type != ET_ButtonPress && event->type != ET_KeyPress)
return FALSE;
@ -4049,7 +4186,7 @@ CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor)
if (focus) {
for (; i < focus->traceGood; i++) {
pWin = focus->trace[i];
if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event,
if (CheckPassiveGrabsOnWindow(pWin, device, ievent,
sendCore, TRUE)) {
ret = TRUE;
goto out;
@ -4064,7 +4201,7 @@ CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor)
for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) {
pWin = device->spriteInfo->sprite->spriteTrace[i];
if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event,
if (CheckPassiveGrabsOnWindow(pWin, device, ievent,
sendCore, TRUE)) {
ret = TRUE;
goto out;
@ -4332,7 +4469,7 @@ FreezeThisEventIfNeededForSyncGrab(DeviceIntPtr thisDev, InternalEvent *event)
case FREEZE_NEXT_EVENT:
grabinfo->sync.state = FROZEN_WITH_EVENT;
FreezeThaw(thisDev, TRUE);
*grabinfo->sync.event = *event;
CopyPartialInternalEvent(grabinfo->sync.event, event);
break;
}
}

362
dix/gestures.c Normal file
View File

@ -0,0 +1,362 @@
/*
* Copyright © 2011 Collabra Ltd.
* Copyright © 2011 Red Hat, Inc.
* Copyright © 2020 Povilas Kanapickas <povilas@radix.lt>
*
* 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "inputstr.h"
#include "scrnintstr.h"
#include "dixgrabs.h"
#include "eventstr.h"
#include "exevents.h"
#include "exglobals.h"
#include "inpututils.h"
#include "eventconvert.h"
#include "windowstr.h"
#include "mi.h"
#define GESTURE_HISTORY_SIZE 100
Bool
GestureInitGestureInfo(GestureInfoPtr gi)
{
memset(gi, 0, sizeof(*gi));
gi->sprite.spriteTrace = calloc(32, sizeof(*gi->sprite.spriteTrace));
if (!gi->sprite.spriteTrace) {
return FALSE;
}
gi->sprite.spriteTraceSize = 32;
gi->sprite.spriteTrace[0] = screenInfo.screens[0]->root;
gi->sprite.hot.pScreen = screenInfo.screens[0];
gi->sprite.hotPhys.pScreen = screenInfo.screens[0];
return TRUE;
}
/**
* Given an event type returns the associated gesture event info.
*/
GestureInfoPtr
GestureFindActiveByEventType(DeviceIntPtr dev, int type)
{
GestureClassPtr g = dev->gesture;
enum EventType type_to_expect = GestureTypeToBegin(type);
if (!g || type_to_expect == 0 || !g->gesture.active ||
g->gesture.type != type_to_expect) {
return NULL;
}
return &g->gesture;
}
/**
* Sets up gesture info for a new gesture. Returns NULL on failure.
*/
GestureInfoPtr
GestureBeginGesture(DeviceIntPtr dev, InternalEvent *ev)
{
GestureClassPtr g = dev->gesture;
enum EventType gesture_type = GestureTypeToBegin(ev->any.type);
/* Note that we ignore begin events when an existing gesture is active */
if (!g || gesture_type == 0 || g->gesture.active)
return NULL;
g->gesture.type = gesture_type;
if (!GestureBuildSprite(dev, &g->gesture))
return NULL;
g->gesture.active = TRUE;
g->gesture.num_touches = ev->gesture_event.num_touches;
g->gesture.sourceid = ev->gesture_event.sourceid;
g->gesture.has_listener = FALSE;
return &g->gesture;
}
/**
* Releases a gesture: this must only be called after all events
* related to that gesture have been sent and finalised.
*/
void
GestureEndGesture(GestureInfoPtr gi)
{
if (gi->has_listener) {
if (gi->listener.grab) {
FreeGrab(gi->listener.grab);
gi->listener.grab = NULL;
}
gi->listener.listener = 0;
gi->has_listener = FALSE;
}
gi->active = FALSE;
gi->num_touches = 0;
gi->sprite.spriteTraceGood = 0;
}
/**
* Ensure a window trace is present in gi->sprite, constructing one for
* Gesture{Pinch,Swipe}Begin events.
*/
Bool
GestureBuildSprite(DeviceIntPtr sourcedev, GestureInfoPtr gi)
{
SpritePtr sprite = &gi->sprite;
if (!sourcedev->spriteInfo->sprite)
return FALSE;
if (!CopySprite(sourcedev->spriteInfo->sprite, sprite))
return FALSE;
if (sprite->spriteTraceGood <= 0)
return FALSE;
return TRUE;
}
/**
* @returns TRUE if the specified grab or selection is the current owner of
* the gesture sequence.
*/
Bool
GestureResourceIsOwner(GestureInfoPtr gi, XID resource)
{
return (gi->listener.listener == resource);
}
void
GestureAddListener(GestureInfoPtr gi, XID resource, int resource_type,
enum GestureListenerType type, WindowPtr window, const GrabPtr grab)
{
GrabPtr g = NULL;
BUG_RETURN(gi->has_listener);
/* We need a copy of the grab, not the grab itself since that may be deleted by
* a UngrabButton request and leaves us with a dangling pointer */
if (grab)
g = AllocGrab(grab);
gi->listener.listener = resource;
gi->listener.resource_type = resource_type;
gi->listener.type = type;
gi->listener.window = window;
gi->listener.grab = g;
gi->has_listener = TRUE;
}
static void
GestureAddGrabListener(DeviceIntPtr dev, GestureInfoPtr gi, GrabPtr grab)
{
enum GestureListenerType type;
/* FIXME: owner_events */
if (grab->grabtype == XI2) {
if (xi2mask_isset(grab->xi2mask, dev, XI_GesturePinchBegin) ||
xi2mask_isset(grab->xi2mask, dev, XI_GestureSwipeBegin)) {
type = GESTURE_LISTENER_GRAB;
} else
type = GESTURE_LISTENER_NONGESTURE_GRAB;
}
else if (grab->grabtype == XI || grab->grabtype == CORE) {
type = GESTURE_LISTENER_NONGESTURE_GRAB;
}
else {
BUG_RETURN_MSG(1, "Unsupported grab type\n");
}
/* grab listeners are always RT_NONE since we keep the grab pointer */
GestureAddListener(gi, grab->resource, RT_NONE, type, grab->window, grab);
}
/**
* Add one listener if there is a grab on the given window.
*/
static void
GestureAddPassiveGrabListener(DeviceIntPtr dev, GestureInfoPtr gi, WindowPtr win, InternalEvent *ev)
{
Bool activate = FALSE;
Bool check_core = FALSE;
GrabPtr grab = CheckPassiveGrabsOnWindow(win, dev, ev, check_core,
activate);
if (!grab)
return;
/* We'll deliver later in gesture-specific code */
ActivateGrabNoDelivery(dev, grab, ev, ev);
GestureAddGrabListener(dev, gi, grab);
}
static void
GestureAddRegularListener(DeviceIntPtr dev, GestureInfoPtr gi, WindowPtr win, InternalEvent *ev)
{
InputClients *iclients = NULL;
OtherInputMasks *inputMasks = NULL;
uint16_t evtype = GetXI2Type(ev->any.type);
int mask;
mask = EventIsDeliverable(dev, ev->any.type, win);
if (!mask)
return;
inputMasks = wOtherInputMasks(win);
if (mask & EVENT_XI2_MASK) {
nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
if (!xi2mask_isset(iclients->xi2mask, dev, evtype))
continue;
GestureAddListener(gi, iclients->resource, RT_INPUTCLIENT,
GESTURE_LISTENER_REGULAR, win, NULL);
return;
}
}
}
void
GestureSetupListener(DeviceIntPtr dev, GestureInfoPtr gi, InternalEvent *ev)
{
int i;
SpritePtr sprite = &gi->sprite;
WindowPtr win;
/* Any current grab will consume all gesture events */
if (dev->deviceGrab.grab) {
GestureAddGrabListener(dev, gi, dev->deviceGrab.grab);
return;
}
/* Find passive grab that would be activated by this event, if any. If we're handling
* ReplayDevice then the search starts from the descendant of the grab window, otherwise
* the search starts at the root window. The search ends at deepest child window. */
i = 0;
if (syncEvents.playingEvents) {
while (i < dev->spriteInfo->sprite->spriteTraceGood) {
if (dev->spriteInfo->sprite->spriteTrace[i++] == syncEvents.replayWin)
break;
}
}
for (; i < sprite->spriteTraceGood; i++) {
win = sprite->spriteTrace[i];
GestureAddPassiveGrabListener(dev, gi, win, ev);
if (gi->has_listener)
return;
}
/* Find the first client with an applicable event selection,
* going from deepest child window back up to the root window. */
for (i = sprite->spriteTraceGood - 1; i >= 0; i--) {
win = sprite->spriteTrace[i];
GestureAddRegularListener(dev, gi, win, ev);
if (gi->has_listener)
return;
}
}
/* As gesture grabs don't turn into active grabs with their own resources, we
* need to walk all the gestures and remove this grab from listener */
void
GestureListenerGone(XID resource)
{
GestureInfoPtr gi;
DeviceIntPtr dev;
InternalEvent *events = InitEventList(GetMaximumEventsNum());
if (!events)
FatalError("GestureListenerGone: couldn't allocate events\n");
for (dev = inputInfo.devices; dev; dev = dev->next) {
if (!dev->gesture)
continue;
gi = &dev->gesture->gesture;
if (!gi->active)
continue;
if (CLIENT_BITS(gi->listener.listener) == resource)
GestureEndGesture(gi);
}
FreeEventList(events, GetMaximumEventsNum());
}
/**
* End physically active gestures for a device.
*/
void
GestureEndActiveGestures(DeviceIntPtr dev)
{
GestureClassPtr g = dev->gesture;
InternalEvent *eventlist;
if (!g)
return;
eventlist = InitEventList(GetMaximumEventsNum());
input_lock();
mieqProcessInputEvents();
if (g->gesture.active) {
int j;
int type = GetXI2Type(GestureTypeToEnd(g->gesture.type));
int nevents = GetGestureEvents(eventlist, dev, type, g->gesture.num_touches,
0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
for (j = 0; j < nevents; j++)
mieqProcessDeviceEvent(dev, eventlist + j, NULL);
}
input_unlock();
FreeEventList(eventlist, GetMaximumEventsNum());
}
/**
* Generate and deliver a Gesture{Pinch,Swipe}End event to the owner.
*
* @param dev The device to deliver the event for.
* @param gi The gesture record to deliver the event for.
*/
void
GestureEmitGestureEndToOwner(DeviceIntPtr dev, GestureInfoPtr gi)
{
InternalEvent event;
/* We're not processing a gesture end for a frozen device */
if (dev->deviceGrab.sync.frozen)
return;
DeliverDeviceClassesChangedEvent(gi->sourceid, GetTimeInMillis());
InitGestureEvent(&event, dev, GetTimeInMillis(), GestureTypeToEnd(gi->type),
0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
DeliverGestureEventToOwner(dev, gi, &event);
}

View File

@ -1874,7 +1874,7 @@ int
GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
uint16_t type, uint32_t flags, const ValuatorMask *mask_in)
{
ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
ScreenPtr scr;
TouchClassPtr t = dev->touch;
ValuatorClassPtr v = dev->valuator;
DeviceEvent *event;
@ -1989,6 +1989,8 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
if (need_rawevent)
set_raw_valuators(raw, &mask, FALSE, raw->valuators.data);
scr = dev->spriteInfo->sprite->hotPhys.pScreen;
/* Indirect device touch coordinates are not used for cursor positioning.
* They are merely informational, and are provided in device coordinates.
* The device sprite is used for positioning instead, and it is already
@ -2099,3 +2101,139 @@ PostSyntheticMotion(DeviceIntPtr pDev,
/* FIXME: MD/SD considerations? */
(*pDev->public.processInputProc) ((InternalEvent *) &ev, pDev);
}
void
InitGestureEvent(InternalEvent *ievent, DeviceIntPtr dev, CARD32 ms,
int type, uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x, double delta_unaccel_y,
double scale, double delta_angle)
{
ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
GestureEvent *event = &ievent->gesture_event;
double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */
init_gesture_event(event, dev, ms);
screenx = dev->spriteInfo->sprite->hotPhys.x;
screeny = dev->spriteInfo->sprite->hotPhys.y;
event->type = type;
event->root = scr->root->drawable.id;
event->root_x = screenx - scr->x;
event->root_y = screeny - scr->y;
event->num_touches = num_touches;
event->flags = flags;
event->delta_x = delta_x;
event->delta_y = delta_y;
event->delta_unaccel_x = delta_unaccel_x;
event->delta_unaccel_y = delta_unaccel_y;
event->scale = scale;
event->delta_angle = delta_angle;
}
/**
* Get events for a pinch or swipe gesture.
*
* events is not NULL-terminated; the return value is the number of events.
* The DDX is responsible for allocating the event structure in the first
* place via GetMaximumEventsNum(), and for freeing it.
*
* @param[out] events The list of events generated
* @param dev The device to generate the events for
* @param type XI_Gesture{Pinch,Swipe}{Begin,Update,End}
* @prama num_touches The number of touches in the gesture
* @param flags Event flags
* @param delta_x,delta_y accelerated relative motion delta
* @param delta_unaccel_x,delta_unaccel_y unaccelerated relative motion delta
* @param scale (valid only to pinch events) absolute scale of a pinch gesture
* @param delta_angle (valid only to pinch events) the ange delta in degrees between the last and
* the current pinch event.
*/
int
GetGestureEvents(InternalEvent *events, DeviceIntPtr dev,
uint16_t type, uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x, double delta_unaccel_y,
double scale, double delta_angle)
{
GestureClassPtr g = dev->gesture;
CARD32 ms = GetTimeInMillis();
enum EventType evtype;
int num_events = 0;
uint32_t evflags = 0;
if (!dev->enabled || !g)
return 0;
if (!IsMaster(dev))
events = UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT,
&num_events);
switch (type) {
case XI_GesturePinchBegin:
evtype = ET_GesturePinchBegin;
break;
case XI_GesturePinchUpdate:
evtype = ET_GesturePinchUpdate;
break;
case XI_GesturePinchEnd:
evtype = ET_GesturePinchEnd;
if (flags & XIGesturePinchEventCancelled)
evflags |= GESTURE_CANCELLED;
break;
case XI_GestureSwipeBegin:
evtype = ET_GestureSwipeBegin;
break;
case XI_GestureSwipeUpdate:
evtype = ET_GestureSwipeUpdate;
break;
case XI_GestureSwipeEnd:
evtype = ET_GestureSwipeEnd;
if (flags & XIGestureSwipeEventCancelled)
evflags |= GESTURE_CANCELLED;
break;
default:
return 0;
}
InitGestureEvent(events, dev, ms, evtype, num_touches, evflags,
delta_x, delta_y, delta_unaccel_x, delta_unaccel_y,
scale, delta_angle);
num_events++;
return num_events;
}
void
QueueGesturePinchEvents(DeviceIntPtr dev, uint16_t type,
uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x,
double delta_unaccel_y,
double scale, double delta_angle)
{
int nevents;
nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags,
delta_x, delta_y,
delta_unaccel_x, delta_unaccel_y,
scale, delta_angle);
queueEventList(dev, InputEventList, nevents);
}
void
QueueGestureSwipeEvents(DeviceIntPtr dev, uint16_t type,
uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x,
double delta_unaccel_y)
{
int nevents;
nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags,
delta_x, delta_y,
delta_unaccel_x, delta_unaccel_y,
0.0, 0.0);
queueEventList(dev, InputEventList, nevents);
}

View File

@ -716,3 +716,10 @@ GrabIsKeyboardGrab(GrabPtr grab)
return (grab->type == KeyPress ||
grab->type == DeviceKeyPress || grab->type == XI_KeyPress);
}
Bool
GrabIsGestureGrab(GrabPtr grab)
{
return (grab->type == XI_GesturePinchBegin ||
grab->type == XI_GestureSwipeBegin);
}

View File

@ -746,6 +746,21 @@ init_device_event(DeviceEvent *event, DeviceIntPtr dev, Time ms,
event->source_type = source_type;
}
/**
* Initializes the given gesture event to zero (or default values),
* for the given device.
*/
void
init_gesture_event(GestureEvent *event, DeviceIntPtr dev, Time ms)
{
memset(event, 0, sizeof(GestureEvent));
event->header = ET_Internal;
event->length = sizeof(GestureEvent);
event->time = ms;
event->deviceid = dev->id;
event->sourceid = dev->id;
}
int
event_get_corestate(DeviceIntPtr mouse, DeviceIntPtr kbd)
{
@ -794,6 +809,24 @@ event_set_state(DeviceIntPtr mouse, DeviceIntPtr kbd, DeviceEvent *event)
}
}
void
event_set_state_gesture(DeviceIntPtr kbd, GestureEvent *event)
{
if (kbd && kbd->key) {
XkbStatePtr state= &kbd->key->xkbInfo->state;
event->mods.base = state->base_mods;
event->mods.latched = state->latched_mods;
event->mods.locked = state->locked_mods;
event->mods.effective = state->mods;
event->group.base = state->base_group;
event->group.latched = state->latched_group;
event->group.locked = state->locked_group;
event->group.effective = state->group;
}
}
/**
* Return the event filter mask for the given device and the given core or
* XI1 protocol type.

View File

@ -12,6 +12,7 @@ srcs_dix = [
'eventconvert.c',
'extension.c',
'gc.c',
'gestures.c',
'getevents.c',
'globals.c',
'glyphcurs.c',

View File

@ -155,14 +155,13 @@ dixMovePrivates(PrivatePtr *privates, int new_offset, unsigned bytes)
static Bool
fixupOneScreen(ScreenPtr pScreen, FixupFunc fixup, unsigned bytes)
{
intptr_t dist;
char *old;
uintptr_t old;
char *new;
DevPrivateKey *keyp, key;
DevPrivateType type;
int size;
old = (char *) pScreen->devPrivates;
old = (uintptr_t) pScreen->devPrivates;
size = global_keys[PRIVATE_SCREEN].offset;
if (!fixup (&pScreen->devPrivates, size, bytes))
return FALSE;
@ -182,9 +181,7 @@ fixupOneScreen(ScreenPtr pScreen, FixupFunc fixup, unsigned bytes)
if (fixup == dixMovePrivates)
new += bytes;
dist = new - old;
if (dist) {
if ((uintptr_t) new != old) {
for (type = PRIVATE_XSELINUX; type < PRIVATE_LAST; type++)
/* Walk the privates list, being careful as the
@ -199,10 +196,11 @@ fixupOneScreen(ScreenPtr pScreen, FixupFunc fixup, unsigned bytes)
* is contained within the allocation. Privates
* stored elsewhere will be left alone
*/
if (old <= (char *) key && (char *) key < old + size)
if (old <= (uintptr_t) key && (uintptr_t) key < old + size)
{
/* Compute new location of key */
key = (DevPrivateKey) ((char *) key + dist);
/* Compute new location of key (deriving from the new
* allocation to avoid UB) */
key = (DevPrivateKey) (new + ((uintptr_t) key - old));
/* Patch the list */
*keyp = key;

View File

@ -205,7 +205,8 @@ ProcChangeProperty(ClientPtr client)
WindowPtr pWin;
char format, mode;
unsigned long len;
int sizeInBytes, totalSize, err;
int sizeInBytes, err;
uint64_t totalSize;
REQUEST(xChangePropertyReq);
@ -253,7 +254,7 @@ ProcChangeProperty(ClientPtr client)
int
dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
Atom type, int format, int mode, unsigned long len,
void *value, Bool sendevent)
const void *value, Bool sendevent)
{
PropertyPtr pProp;
PropertyRec savedProp;

View File

@ -620,12 +620,15 @@ ilog2(int val)
unsigned int
ResourceClientBits(void)
{
static unsigned int cached = 0;
static unsigned int cache_ilog2 = 0;
static unsigned int cache_limit = 0;
if (cached == 0)
cached = ilog2(LimitClients);
if (LimitClients != cache_limit) {
cache_limit = LimitClients;
cache_ilog2 = ilog2(LimitClients);
}
return cached;
return cache_ilog2;
}
/*****************

View File

@ -42,6 +42,8 @@
#define TOUCH_HISTORY_SIZE 100
Bool touchEmulatePointer = TRUE;
/**
* Some documentation about touch points:
* The driver submits touch events with its own (unique) touch point ID.
@ -142,7 +144,7 @@ TouchBeginDDXTouch(DeviceIntPtr dev, uint32_t ddx_id)
if (!t)
return NULL;
emulate_pointer = (t->mode == XIDirectTouch);
emulate_pointer = touchEmulatePointer && (t->mode == XIDirectTouch);
/* Look for another active touchpoint with the same DDX ID. DDX
* touchpoints must be unique. */

View File

@ -3642,7 +3642,7 @@ SetRootClip(ScreenPtr pScreen, int enable)
if (!pWin)
return;
WasViewable = (Bool) (pWin->viewable);
if (WasViewable) {
if (WasViewable && mode != ROOT_CLIP_INPUT_ONLY) {
for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
(void) (*pScreen->MarkOverlappedWindows) (pChild,
pChild, &pLayerWin);
@ -3696,7 +3696,7 @@ SetRootClip(ScreenPtr pScreen, int enable)
ResizeChildrenWinSize(pWin, 0, 0, 0, 0);
if (WasViewable) {
if (WasViewable && mode != ROOT_CLIP_INPUT_ONLY) {
if (pWin->firstChild) {
anyMarked |= (*pScreen->MarkOverlappedWindows) (pWin->firstChild,
pWin->firstChild,

64
doc/dtrace/meson.build Normal file
View File

@ -0,0 +1,64 @@
if build_docs
basename = 'Xserver-DTrace'
input_xml = basename + '.xml'
custom_target(
basename + '.html',
output: basename + '.html',
input: [input_xml],
command: [xmlto] + docs_xmlto_search_flags + [
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-xhtml.xsl'),
'--stringparam', 'target.database.document=' + join_paths(doc_sgml_path, 'X11/dbs/masterdb.html.xml'),
'--stringparam', 'current.docid=' + basename,
'-o', meson.current_build_dir(),
'xhtml-nochunks', '@INPUT0@'],
build_by_default: true,
install: true,
install_dir: join_paths(get_option('datadir'), 'doc/xorg-server'),
)
if build_docs_pdf
foreach format : ['ps', 'pdf']
output_fn = basename + '.' + format
custom_target(
output_fn,
output: output_fn,
input: [input_xml],
command: [xmlto] + docs_xmlto_search_flags + [
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-fo.xsl'),
'--stringparam', 'img.src.path=' + meson.current_build_dir(),
'--stringparam', 'target.database.document=' + join_paths(doc_sgml_path, 'X11/dbs/masterdb.pdf.xml'),
'--stringparam', 'current.docid=' + basename,
'-o', meson.current_build_dir(),
'--with-fop', format, '@INPUT0@'],
build_by_default: true,
install: true,
install_dir: join_paths(get_option('datadir'), 'doc/xorg-server'),
)
endforeach
endif
foreach format_data : [['html', 'xorg-xhtml.xsl'], ['pdf', 'xorg-fo.xsl']]
format = format_data[0]
stylesheet = format_data[1]
output_fn = basename + '.' + format + '.db'
custom_target(
output_fn,
output: output_fn,
input: [input_xml],
command: [xsltproc] + docs_xslt_search_flags + [
'--stringparam', 'targets.filename', output_fn,
'--stringparam', 'collect.xref.targets', 'only',
'--stringparam', 'olink.base.uri', basename + '.' + format,
'--nonet',
'--output', join_paths(meson.current_build_dir(), output_fn),
'--xinclude', join_paths(doc_stylesheet_srcdir, stylesheet),
'@INPUT0@'],
build_by_default: true,
install: true,
install_dir: join_paths(get_option('datadir'), 'doc/xorg-server'),
)
endforeach
endif

39
doc/meson.build Normal file
View File

@ -0,0 +1,39 @@
if build_docs_devel
foreach basename : ['Xserver-spec', 'Xinput']
input_xml = basename + '.xml'
custom_target(
basename + '.html',
output: basename + '.html',
input: [input_xml],
command: [xmlto] + docs_xmlto_search_flags + [
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-xhtml.xsl'),
'-o', meson.current_build_dir(),
'xhtml-nochunks', '@INPUT0@'],
build_by_default: true,
install: false,
)
if build_docs_pdf
foreach format : ['ps', 'pdf']
output_fn = basename + '.' + format
custom_target(
output_fn,
output: output_fn,
input: [input_xml],
command: [xmlto] + docs_xmlto_search_flags + [
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-fo.xsl'),
'--stringparam', 'img.src.path=' + meson.current_build_dir(),
'-o', meson.current_build_dir(),
'--with-fop', format, '@INPUT0@'],
build_by_default: true,
install: false,
)
endforeach
endif
endforeach
endif
subdir('dtrace')

View File

@ -1,105 +0,0 @@
#
# Generate output formats for a single DocBook/XML with/without chapters
#
# Variables set by the calling Makefile:
# shelfdir: the location where the docs/specs are installed. Typically $(docdir)
# docbook: the main DocBook/XML file, no chapters, appendix or image files
# chapters: all files pulled in by an XInclude statement and images.
#
#
# This makefile is intended for Users Documentation and Functional Specifications.
# Do not use for Developer Documentation which is not installed and does not require olink.
# Refer to http://www.x.org/releases/X11R7.6/doc/xorg-docs/ReleaseNotes.html#id2584393
# for an explanation on documents classification.
#
# DocBook/XML generated output formats to be installed
shelf_DATA =
# DocBook/XML file with chapters, appendix and images it includes
dist_shelf_DATA = $(docbook) $(chapters)
if HAVE_XMLTO
if HAVE_STYLESHEETS
XMLTO_SEARCHPATH_FLAGS = \
--searchpath "$(XORG_SGML_PATH)/X11" \
--searchpath "$(abs_top_builddir)"
XMLTO_HTML_OLINK_FLAGS = \
--stringparam target.database.document=$(XORG_SGML_PATH)/X11/dbs/masterdb.html.xml \
--stringparam current.docid="$(<:.xml=)"
XMLTO_HTML_STYLESHEET_FLAGS = -x $(STYLESHEET_SRCDIR)/xorg-xhtml.xsl
XMLTO_HTML_FLAGS = \
$(XMLTO_SEARCHPATH_FLAGS) \
$(XMLTO_HTML_STYLESHEET_FLAGS) \
$(XMLTO_HTML_OLINK_FLAGS)
shelf_DATA += $(docbook:.xml=.html)
%.html: %.xml $(chapters)
$(AM_V_GEN)$(XMLTO) $(XMLTO_HTML_FLAGS) xhtml-nochunks $<
if HAVE_XMLTO_TEXT
shelf_DATA += $(docbook:.xml=.txt)
%.txt: %.xml $(chapters)
$(AM_V_GEN)$(XMLTO) $(XMLTO_HTML_FLAGS) txt $<
endif HAVE_XMLTO_TEXT
if HAVE_FOP
XMLTO_FO_IMAGEPATH_FLAGS = --stringparam img.src.path=$(abs_builddir)/
XMLTO_PDF_OLINK_FLAGS = \
--stringparam target.database.document=$(XORG_SGML_PATH)/X11/dbs/masterdb.pdf.xml \
--stringparam current.docid="$(<:.xml=)"
XMLTO_FO_STYLESHEET_FLAGS = -x $(STYLESHEET_SRCDIR)/xorg-fo.xsl
XMLTO_FO_FLAGS = \
$(XMLTO_SEARCHPATH_FLAGS) \
$(XMLTO_FO_STYLESHEET_FLAGS) \
$(XMLTO_FO_IMAGEPATH_FLAGS) \
$(XMLTO_PDF_OLINK_FLAGS)
shelf_DATA += $(docbook:.xml=.pdf)
%.pdf: %.xml $(chapters)
$(AM_V_GEN)$(XMLTO) $(XMLTO_FO_FLAGS) --with-fop pdf $<
shelf_DATA += $(docbook:.xml=.ps)
%.ps: %.xml $(chapters)
$(AM_V_GEN)$(XMLTO) $(XMLTO_FO_FLAGS) --with-fop ps $<
endif HAVE_FOP
# Generate documents cross-reference target databases
if HAVE_XSLTPROC
XSLT_SEARCHPATH_FLAGS = \
--path "$(XORG_SGML_PATH)/X11" \
--path "$(abs_top_builddir)"
XSLT_OLINK_FLAGS = \
--stringparam targets.filename "$@" \
--stringparam collect.xref.targets "only" \
--stringparam olink.base.uri "$(@:.db=)"
XSLT_HTML_FLAGS = \
$(XSLT_SEARCHPATH_FLAGS) \
$(XSLT_OLINK_FLAGS) \
--nonet --xinclude \
$(STYLESHEET_SRCDIR)/xorg-xhtml.xsl
XSLT_PDF_FLAGS = \
$(XSLT_SEARCHPATH_FLAGS) \
$(XSLT_OLINK_FLAGS) \
--nonet --xinclude \
$(STYLESHEET_SRCDIR)/xorg-fo.xsl
shelf_DATA += $(docbook:.xml=.html.db)
%.html.db: %.xml $(chapters)
$(AM_V_GEN)$(XSLTPROC) $(XSLT_HTML_FLAGS) $<
shelf_DATA += $(docbook:.xml=.pdf.db)
%.pdf.db: %.xml $(chapters)
$(AM_V_GEN)$(XSLTPROC) $(XSLT_PDF_FLAGS) $<
endif HAVE_XSLTPROC
endif HAVE_STYLESHEETS
endif HAVE_XMLTO
CLEANFILES = $(shelf_DATA)

View File

@ -216,7 +216,7 @@ glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
w <= glamor_priv->glyph_max_dim &&
h <= glamor_priv->glyph_max_dim)
|| (w == 0 && h == 0)
|| !glamor_priv->formats[depth].format))
|| !glamor_priv->formats[depth].rendering_supported))
return fbCreatePixmap(screen, w, h, depth, usage);
else
pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
@ -414,6 +414,7 @@ glamor_debug_output_callback(GLenum source,
LogMessageVerb(X_ERROR, 0, "glamor%d: GL error: %*s\n",
screen->myNum, length, message);
xorg_backtrace();
}
/**
@ -460,7 +461,8 @@ glamor_format_for_pixmap(PixmapPtr pixmap)
static void
glamor_add_format(ScreenPtr screen, int depth, CARD32 render_format,
GLenum internalformat, GLenum format, GLenum type)
GLenum internalformat, GLenum format, GLenum type,
Bool rendering_supported)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
struct glamor_format *f = &glamor_priv->formats[depth];
@ -475,7 +477,7 @@ glamor_add_format(ScreenPtr screen, int depth, CARD32 render_format,
* Note that we can't just create a pixmap because we're in
* screeninit.
*/
if (glamor_priv->is_gles) {
if (rendering_supported && glamor_priv->is_gles) {
unsigned fbo, tex;
int read_format, read_type;
GLenum status;
@ -520,6 +522,7 @@ glamor_add_format(ScreenPtr screen, int depth, CARD32 render_format,
f->internalformat = internalformat;
f->format = format;
f->type = type;
f->rendering_supported = rendering_supported;
}
/* Set up the GL format/types that glamor will use for the various depths
@ -550,11 +553,15 @@ glamor_setup_formats(ScreenPtr screen)
* only falling back to a8 if we can't do them.
*/
if (glamor_priv->is_gles || epoxy_has_gl_extension("GL_ARB_texture_rg")) {
glamor_add_format(screen, 1, PICT_a1,
GL_R8, GL_RED, GL_UNSIGNED_BYTE, FALSE);
glamor_add_format(screen, 8, PICT_a8,
GL_R8, GL_RED, GL_UNSIGNED_BYTE);
GL_R8, GL_RED, GL_UNSIGNED_BYTE, TRUE);
} else {
glamor_add_format(screen, 1, PICT_a1,
GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, FALSE);
glamor_add_format(screen, 8, PICT_a8,
GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE);
GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, TRUE);
}
if (glamor_priv->is_gles) {
@ -568,40 +575,41 @@ glamor_setup_formats(ScreenPtr screen)
* disable render accel for now.
*/
glamor_add_format(screen, 15, PICT_x1r5g5b5,
GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, TRUE);
} else {
glamor_add_format(screen, 15, PICT_x1r5g5b5,
GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV);
GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, TRUE);
}
glamor_add_format(screen, 16, PICT_r5g6b5,
GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, TRUE);
if (glamor_priv->is_gles) {
assert(X_BYTE_ORDER == X_LITTLE_ENDIAN);
glamor_add_format(screen, 24, PICT_x8b8g8r8,
GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, TRUE);
glamor_add_format(screen, 32, PICT_a8b8g8r8,
GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, TRUE);
} else {
glamor_add_format(screen, 24, PICT_x8r8g8b8,
GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV);
GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, TRUE);
glamor_add_format(screen, 32, PICT_a8r8g8b8,
GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV);
GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, TRUE);
}
if (glamor_priv->is_gles) {
glamor_add_format(screen, 30, PICT_x2b10g10r10,
GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV);
GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, TRUE);
} else {
glamor_add_format(screen, 30, PICT_x2r10g10b10,
GL_RGB10_A2, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV);
GL_RGB10_A2, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, TRUE);
}
glamor_priv->cbcr_format.depth = 16;
glamor_priv->cbcr_format.internalformat = GL_RG8;
glamor_priv->cbcr_format.format = GL_RG;
glamor_priv->cbcr_format.type = GL_UNSIGNED_BYTE;
glamor_priv->cbcr_format.rendering_supported = TRUE;
}
/** Set up glamor for an already-configured GL context. */
@ -610,10 +618,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
{
glamor_screen_private *glamor_priv;
int gl_version;
int glsl_major, glsl_minor;
int max_viewport_size[2];
const char *shading_version_string;
int shading_version_offset;
PictureScreenPtr ps = GetPictureScreenIfSet(screen);
@ -662,9 +667,6 @@ glamor_init(ScreenPtr screen, unsigned int flags)
* register correct close screen function. */
if (flags & GLAMOR_USE_EGL_SCREEN) {
glamor_egl_screen_init(screen, &glamor_priv->ctx);
} else {
if (!glamor_glx_screen_init(&glamor_priv->ctx))
goto fail;
}
glamor_make_current(glamor_priv);
@ -678,29 +680,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
glamor_priv->is_core_profile =
gl_version >= 31 && !epoxy_has_gl_extension("GL_ARB_compatibility");
shading_version_string = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
if (!shading_version_string) {
LogMessage(X_WARNING,
"glamor%d: Failed to get GLSL version\n",
screen->myNum);
goto fail;
}
shading_version_offset = 0;
if (strncmp("OpenGL ES GLSL ES ", shading_version_string, 18) == 0)
shading_version_offset = 18;
if (sscanf(shading_version_string + shading_version_offset,
"%i.%i",
&glsl_major,
&glsl_minor) != 2) {
LogMessage(X_WARNING,
"glamor%d: Failed to parse GLSL version string %s\n",
screen->myNum, shading_version_string);
goto fail;
}
glamor_priv->glsl_version = glsl_major * 100 + glsl_minor;
glamor_priv->glsl_version = epoxy_glsl_version();
if (glamor_priv->is_gles) {
/* Force us back to the base version of our programs on an ES
@ -745,7 +725,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
* have instanced arrays, but this is not always the case.
* etnaviv offers GLSL 140 with OpenGL 2.1.
*/
if (glamor_priv->glsl_version >= 130 &&
if (glamor_glsl_has_ints(glamor_priv) &&
!epoxy_has_gl_extension("GL_ARB_instanced_arrays"))
glamor_priv->glsl_version = 120;
} else {
@ -771,6 +751,10 @@ glamor_init(ScreenPtr screen, unsigned int flags)
goto fail;
}
if (!glamor_priv->is_gles && glamor_priv->glsl_version == 120 &&
epoxy_has_gl_extension("GL_ARB_instanced_arrays"))
glamor_priv->use_gpu_shader4 = epoxy_has_gl_extension("GL_EXT_gpu_shader4");
glamor_priv->has_rw_pbo = FALSE;
if (!glamor_priv->is_gles)
glamor_priv->has_rw_pbo = TRUE;
@ -798,7 +782,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
epoxy_gl_version() >= 30 ||
epoxy_has_gl_extension("GL_NV_pack_subimage");
glamor_priv->has_dual_blend =
glamor_priv->glsl_version >= 130 &&
glamor_glsl_has_ints(glamor_priv) &&
epoxy_has_gl_extension("GL_ARB_blend_func_extended");
glamor_priv->has_clear_texture =
epoxy_gl_version() >= 44 ||
@ -816,7 +800,8 @@ glamor_init(ScreenPtr screen, unsigned int flags)
* cached IB.
*/
if (strstr((char *)glGetString(GL_VENDOR), "Broadcom") &&
strstr((char *)glGetString(GL_RENDERER), "VC4"))
(strstr((char *)glGetString(GL_RENDERER), "VC4") ||
strstr((char *)glGetString(GL_RENDERER), "V3D")))
glamor_priv->use_quads = FALSE;
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glamor_priv->max_fbo_size);

View File

@ -208,11 +208,6 @@ static const glamor_facet glamor_facet_composite_glyphs_120 = {
.locations = glamor_program_location_atlas,
};
static inline Bool
glamor_glyph_use_130(glamor_screen_private *glamor_priv) {
return glamor_priv->glsl_version >= 130;
}
static Bool
glamor_glyphs_init_facet(ScreenPtr screen)
{
@ -274,7 +269,7 @@ glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst,
box->y2 - box->y1);
box++;
if (glamor_glyph_use_130(glamor_priv))
if (glamor_glsl_has_ints(glamor_priv))
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nglyph);
else
glamor_glDrawArrays_GL_QUADS(glamor_priv, nglyph);
@ -287,7 +282,7 @@ glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst,
glDisable(GL_SCISSOR_TEST);
if (glamor_glyph_use_130(glamor_priv)) {
if (glamor_glsl_has_ints(glamor_priv)) {
glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
}
@ -305,7 +300,7 @@ glamor_glyph_start(ScreenPtr screen, int count)
/* Set up the vertex buffers for the font and destination */
if (glamor_glyph_use_130(glamor_priv)) {
if (glamor_glsl_has_ints(glamor_priv)) {
v = glamor_get_vbo_space(screen, count * (6 * sizeof (GLshort)), &vbo_offset);
glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
@ -439,7 +434,7 @@ glamor_composite_glyphs(CARD8 op,
/* First glyph in the current atlas?
*/
if (_X_UNLIKELY(glyphs_queued == 0)) {
if (glamor_glyph_use_130(glamor_priv))
if (glamor_glsl_has_ints(glamor_priv))
prog = glamor_setup_program_render(op, src, glyph_pict, dst,
glyphs_program,
&glamor_facet_composite_glyphs_130,
@ -458,7 +453,7 @@ glamor_composite_glyphs(CARD8 op,
*/
glyphs_queued++;
if (_X_LIKELY(glamor_glyph_use_130(glamor_priv))) {
if (_X_LIKELY(glamor_glsl_has_ints(glamor_priv))) {
v[0] = x - glyph->info.x;
v[1] = y - glyph->info.y;
v[2] = glyph_draw->width;

View File

@ -21,29 +21,26 @@
* IN THE SOFTWARE.
*/
#ifndef GLAMOR_CONTEXT_H
#define GLAMOR_CONTEXT_H
#include <epoxy/egl.h>
/**
* @file glamor_context.h
*
* This is the struct of state required for context switching in
* glamor. It has to use types that don't require including either
* server headers or Xlib headers, since it will be included by both
* the server and the GLX (xlib) code.
* glamor. Initially this was abstracted away from EGL, and
* presumably it would need to be again if someone wanted to use
* glamor with WGL/CGL.
*/
struct glamor_context {
/** Either an EGLDisplay or an Xlib Display */
void *display;
/** Either a GLXContext or an EGLContext. */
void *ctx;
/** The EGLSurface we should MakeCurrent to */
void *drawable;
/** The GLXDrawable we should MakeCurrent to */
uint32_t drawable_xid;
EGLDisplay display;
EGLContext ctx;
EGLSurface surface;
void (*make_current)(struct glamor_context *glamor_ctx);
};
Bool glamor_glx_screen_init(struct glamor_context *glamor_ctx);
#endif

View File

@ -933,8 +933,6 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
{
struct glamor_egl_screen_private *glamor_egl;
const GLubyte *renderer;
EGLConfig egl_config;
int n;
glamor_egl = calloc(sizeof(*glamor_egl), 1);
if (glamor_egl == NULL)
@ -977,6 +975,7 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
}
GLAMOR_CHECK_EGL_EXTENSION(KHR_surfaceless_context);
GLAMOR_CHECK_EGL_EXTENSION(KHR_no_config_context);
if (eglBindAPI(EGL_OPENGL_API)) {
static const EGLint config_attribs_core[] = {
@ -993,12 +992,13 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
};
glamor_egl->context = eglCreateContext(glamor_egl->display,
NULL, EGL_NO_CONTEXT,
EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT,
config_attribs_core);
if (glamor_egl->context == EGL_NO_CONTEXT)
glamor_egl->context = eglCreateContext(glamor_egl->display,
NULL, EGL_NO_CONTEXT,
EGL_NO_CONFIG_KHR,
EGL_NO_CONTEXT,
config_attribs);
}
@ -1029,14 +1029,8 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
goto error;
}
if (!eglChooseConfig(glamor_egl->display, NULL, &egl_config, 1, &n)) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"glamor: No acceptable EGL configs found\n");
goto error;
}
glamor_egl->context = eglCreateContext(glamor_egl->display,
egl_config, EGL_NO_CONTEXT,
EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT,
config_attribs);
if (glamor_egl->context == EGL_NO_CONTEXT) {
@ -1060,9 +1054,14 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
goto error;
}
if (strstr((const char *)renderer, "llvmpipe")) {
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"Refusing to try glamor on llvmpipe\n");
goto error;
if (scrn->confScreen->num_gpu_devices)
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"Allowing glamor on llvmpipe for PRIME\n");
else {
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"Refusing to try glamor on llvmpipe\n");
goto error;
}
}
/*
@ -1085,11 +1084,11 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
"EGL_EXT_image_dma_buf_import") &&
epoxy_has_egl_extension(glamor_egl->display,
"EGL_EXT_image_dma_buf_import_modifiers")) {
if (xf86Info.debug != NULL)
glamor_egl->dmabuf_capable = !!strstr(xf86Info.debug,
"dmabuf_capable");
else
glamor_egl->dmabuf_capable = TRUE;
if (xf86Info.debug != NULL)
glamor_egl->dmabuf_capable = !!strstr(xf86Info.debug,
"dmabuf_capable");
else
glamor_egl->dmabuf_capable = FALSE;
}
#endif

View File

@ -47,7 +47,7 @@ glamor_font_get(ScreenPtr screen, FontPtr font)
unsigned long count;
char *bits;
if (glamor_priv->glsl_version < 130)
if (!glamor_glsl_has_ints(glamor_priv))
return NULL;
privates = FontGetPrivate(font, glamor_font_private_index);
@ -210,7 +210,7 @@ glamor_font_init(ScreenPtr screen)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
if (glamor_priv->glsl_version < 130)
if (!glamor_glsl_has_ints(glamor_priv))
return TRUE;
if (glamor_font_generation != serverGeneration) {

View File

@ -1,68 +0,0 @@
/*
* Copyright © 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.
*/
#include <epoxy/glx.h>
#include "glamor_context.h"
/**
* @file glamor_glx.c
*
* GLX context management for glamor.
*
* This has to be kept separate from the server sources because of
* Xlib's conflicting definition of CARD32 and similar typedefs.
*/
static void
glamor_glx_make_current(struct glamor_context *glamor_ctx)
{
/* There's only a single global dispatch table in Mesa. EGL, GLX,
* and AIGLX's direct dispatch table manipulation don't talk to
* each other. We need to set the context to NULL first to avoid
* GLX's no-op context change fast path when switching back to
* GLX.
*/
glXMakeCurrent(glamor_ctx->display, None, None);
glXMakeCurrent(glamor_ctx->display, glamor_ctx->drawable_xid,
glamor_ctx->ctx);
}
Bool
glamor_glx_screen_init(struct glamor_context *glamor_ctx)
{
glamor_ctx->ctx = glXGetCurrentContext();
if (!glamor_ctx->ctx)
return False;
glamor_ctx->display = glXGetCurrentDisplay();
if (!glamor_ctx->display)
return False;
glamor_ctx->drawable_xid = glXGetCurrentDrawable();
glamor_ctx->make_current = glamor_glx_make_current;
return True;
}

View File

@ -170,6 +170,11 @@ struct glamor_format {
* transferred using format/type.
*/
CARD32 render_format;
/**
* Whether rendering is supported in GL at all (i.e. without pixel data conversion
* just before upload)
*/
Bool rendering_supported;
};
struct glamor_saved_procs {
@ -213,8 +218,14 @@ typedef struct glamor_screen_private {
Bool has_texture_swizzle;
Bool is_core_profile;
Bool can_copyplane;
Bool use_gpu_shader4;
int max_fbo_size;
/**
* Stores information about supported formats. Note, that this list contains all
* supported pixel formats, including these that are not supported on GL side
* directly, but are converted to another format instead.
*/
struct glamor_format formats[33];
struct glamor_format cbcr_format;

View File

@ -187,6 +187,7 @@ fs_location_vars(glamor_program_location locations)
static const char vs_template[] =
"%s" /* version */
"%s" /* exts */
"%s" /* defines */
"%s" /* prim vs_vars */
"%s" /* fill vs_vars */
@ -199,6 +200,7 @@ static const char vs_template[] =
static const char fs_template[] =
"%s" /* version */
"%s" /* exts */
GLAMOR_DEFAULT_PRECISION
"%s" /* defines */
"%s" /* prim fs_vars */
@ -258,10 +260,11 @@ glamor_build_program(ScreenPtr screen,
char *fs_vars = NULL;
char *vs_vars = NULL;
char *vs_prog_string;
char *fs_prog_string;
char *vs_prog_string = NULL;
char *fs_prog_string = NULL;
GLint fs_prog, vs_prog;
Bool gpu_shader4 = FALSE;
if (!fill)
fill = &facet_null_fill;
@ -270,8 +273,14 @@ glamor_build_program(ScreenPtr screen,
flags |= fill->flags;
version = MAX(version, fill->version);
if (version > glamor_priv->glsl_version)
goto fail;
if (version > glamor_priv->glsl_version) {
if (version == 130 && !glamor_priv->use_gpu_shader4)
goto fail;
else {
version = 120;
gpu_shader4 = TRUE;
}
}
vs_vars = vs_location_vars(locations);
fs_vars = fs_location_vars(locations);
@ -291,6 +300,7 @@ glamor_build_program(ScreenPtr screen,
if (asprintf(&vs_prog_string,
vs_template,
str(version_string),
gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n" : "",
str(defines),
str(prim->vs_vars),
str(fill->vs_vars),
@ -302,6 +312,7 @@ glamor_build_program(ScreenPtr screen,
if (asprintf(&fs_prog_string,
fs_template,
str(version_string),
gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n#define texelFetch texelFetch2D\n#define uint unsigned int\n" : "",
str(defines),
str(prim->fs_vars),
str(fill->fs_vars),
@ -372,6 +383,8 @@ fail:
glDeleteProgram(prog->prog);
prog->prog = 0;
}
free(vs_prog_string);
free(fs_prog_string);
free(version_string);
free(fs_vars);
free(vs_vars);

View File

@ -69,7 +69,7 @@ glamor_poly_fill_rect_gl(DrawablePtr drawable,
glamor_bounds_union_rect(&bounds, &prect[i]);
}
if (glamor_priv->glsl_version >= 130) {
if (glamor_glsl_has_ints(glamor_priv)) {
prog = glamor_use_program_fill(pixmap, gc,
&glamor_priv->poly_fill_rect_program,
&glamor_facet_polyfillrect_130);
@ -151,7 +151,7 @@ glamor_poly_fill_rect_gl(DrawablePtr drawable,
scissor.y1 + off_y,
scissor.x2 - scissor.x1,
scissor.y2 - scissor.y1);
if (glamor_priv->glsl_version >= 130)
if (glamor_glsl_has_ints(glamor_priv))
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nrect);
else {
glamor_glDrawArrays_GL_QUADS(glamor_priv, nrect);
@ -163,7 +163,7 @@ glamor_poly_fill_rect_gl(DrawablePtr drawable,
bail:
glDisable(GL_SCISSOR_TEST);
if (glamor_priv->glsl_version >= 130) {
if (glamor_glsl_has_ints(glamor_priv)) {
glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);

View File

@ -773,14 +773,19 @@ glamor_render_format_is_supported(PicturePtr picture)
{
PictFormatShort storage_format;
glamor_screen_private *glamor_priv;
struct glamor_format *f;
/* Source-only pictures should always work */
if (!picture->pDrawable)
return TRUE;
glamor_priv = glamor_get_screen_private(picture->pDrawable->pScreen);
storage_format =
glamor_priv->formats[picture->pDrawable->depth].render_format;
f = &glamor_priv->formats[picture->pDrawable->depth];
if (!f->rendering_supported)
return FALSE;
storage_format = f->render_format;
switch (picture->format) {
case PICT_a2r10g10b10:

View File

@ -64,7 +64,7 @@ glamor_fill_spans_gl(DrawablePtr drawable,
glamor_make_current(glamor_priv);
if (glamor_priv->glsl_version >= 130) {
if (glamor_glsl_has_ints(glamor_priv)) {
prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->fill_spans_program,
&glamor_facet_fillspans_130);
@ -134,7 +134,7 @@ glamor_fill_spans_gl(DrawablePtr drawable,
box->x2 - box->x1,
box->y2 - box->y1);
box++;
if (glamor_priv->glsl_version >= 130)
if (glamor_glsl_has_ints(glamor_priv))
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, n);
else {
glamor_glDrawArrays_GL_QUADS(glamor_priv, n);
@ -146,7 +146,7 @@ glamor_fill_spans_gl(DrawablePtr drawable,
bail:
glDisable(GL_SCISSOR_TEST);
if (glamor_priv->glsl_version >= 130)
if (glamor_glsl_has_ints(glamor_priv))
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);

View File

@ -732,5 +732,9 @@ glamor_glDrawArrays_GL_QUADS(glamor_screen_private *glamor_priv, unsigned count)
}
}
static inline Bool
glamor_glsl_has_ints(glamor_screen_private *glamor_priv) {
return glamor_priv->glsl_version >= 130 || glamor_priv->use_gpu_shader4;
}
#endif

View File

@ -4,7 +4,6 @@ srcs_glamor = [
'glamor_core.c',
'glamor_dash.c',
'glamor_font.c',
'glamor_glx.c',
'glamor_composite_glyphs.c',
'glamor_image.c',
'glamor_lines.c',

View File

@ -487,8 +487,15 @@ __glXGetDrawable(__GLXcontext * glxc, GLXDrawable drawId, ClientPtr client,
__GLXscreen *pGlxScreen;
int rc;
if (validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY,
DixWriteAccess, &pGlxDraw, &rc)) {
rc = dixLookupResourceByType((void **)&pGlxDraw, drawId,
__glXDrawableRes, client, DixWriteAccess);
if (rc == Success &&
/* If pGlxDraw->drawId == drawId, drawId is a valid GLX drawable.
* Otherwise, if pGlxDraw->type == GLX_DRAWABLE_WINDOW, drawId is
* an X window, but the client has already created a GLXWindow
* associated with it, so we don't want to create another one. */
(pGlxDraw->drawId == drawId ||
pGlxDraw->type == GLX_DRAWABLE_WINDOW)) {
if (glxc != NULL &&
glxc->config != NULL &&
glxc->config != pGlxDraw->config) {
@ -655,11 +662,12 @@ xorgGlxMakeCurrent(ClientPtr client, GLXContextTag tag, XID drawId, XID readId,
glxc->readPriv = NULL;
return __glXError(GLXBadContext);
}
glxc->currentClient = client;
glxServer.setContextTagPrivate(client, newContextTag, glxc);
}
glxServer.setContextTagPrivate(client, newContextTag, glxc);
if (glxc)
glxc->currentClient = client;
if (prevglxc) {
prevglxc->currentClient = NULL;
if (!prevglxc->idExists) {
@ -985,7 +993,6 @@ __glXDisp_GetVisualConfigs(__GLXclientState * cl, GLbyte * pc)
/* Pad with zeroes, so that attributes count is constant. */
while (p < GLX_VIS_CONFIG_TOTAL) {
buf[p++] = 0;
buf[p++] = 0;
}
assert(p == GLX_VIS_CONFIG_TOTAL);
@ -1874,7 +1881,7 @@ DoGetDrawableAttributes(__GLXclientState * cl, XID drawId)
int err = dixLookupWindow((WindowPtr *)&pDraw, drawId, client,
DixGetAttrAccess);
if (err != Success)
return error;
return __glXError(GLXBadDrawable);
}
if (pGlxDraw)
pDraw = pGlxDraw->pDraw;

View File

@ -115,6 +115,16 @@ render_type_is_pbuffer_only(unsigned renderType)
| __DRI_ATTRIB_FLOAT_BIT));
}
static int
server_has_depth(int depth)
{
int i;
for (i = 0; i < screenInfo.numPixmapFormats; i++)
if (screenInfo.formats[i].depth == depth)
return 1;
return 0;
}
static __GLXconfig *
createModeFromConfig(const __DRIcoreExtension * core,
const __DRIconfig * driConfig,
@ -178,6 +188,16 @@ createModeFromConfig(const __DRIcoreExtension * core,
if (!render_type_is_pbuffer_only(renderType))
drawableType |= GLX_WINDOW_BIT | GLX_PIXMAP_BIT;
/* Make sure we don't advertise things the server isn't configured for */
if ((drawableType & (GLX_PBUFFER_BIT | GLX_PIXMAP_BIT)) &&
!server_has_depth(config->config.rgbBits)) {
drawableType &= ~(GLX_PBUFFER_BIT | GLX_PIXMAP_BIT);
if (!drawableType) {
free(config);
return NULL;
}
}
config->config.next = NULL;
config->config.visualType = visualType;
config->config.renderType = renderType;

View File

@ -92,6 +92,9 @@ static void SetReplyHeader(ClientPtr client, void *replyPtr)
xGenericReply *rep = (xGenericReply *) replyPtr;
rep->type = X_Reply;
rep->sequenceNumber = client->sequence;
if (client->swapped) {
swaps(&rep->sequenceNumber);
}
rep->length = 0;
}

View File

@ -66,6 +66,11 @@ deprecated, use \fI\-listenfd\fP instead.
Add given fd as a listen socket. This option is used by the \fIWayland\fP
server to pass \fIXwayland\fP the socket where X clients connect.
.TP 8
.B \-noTouchPointerEmulation
Disable touch pointer emulation. This allows the Wayland compositor to
implement its own pointer emulation mechanism for X11 clients that don't
support touch input.
.TP 8
.B \-rootless
Run \fIXwayland\fP rootless, so that X clients integrate seamlessly with
Wayland clients in a Wayland desktop. That requires the Wayland server

View File

@ -4,6 +4,8 @@ srcs = [
'xwayland-input.h',
'xwayland-cursor.c',
'xwayland-cursor.h',
'xwayland-drm-lease.h',
'xwayland-drm-lease.c',
'xwayland-glamor.h',
'xwayland-glx.h',
'xwayland-pixmap.c',
@ -36,12 +38,14 @@ protodir = protocols_dep.get_pkgconfig_variable('pkgdatadir')
pointer_xml = join_paths(protodir, 'unstable', 'pointer-constraints', 'pointer-constraints-unstable-v1.xml')
relative_xml = join_paths(protodir, 'unstable', 'relative-pointer', 'relative-pointer-unstable-v1.xml')
gestures_xml = join_paths(protodir, 'unstable', 'pointer-gestures', 'pointer-gestures-unstable-v1.xml')
tablet_xml = join_paths(protodir, 'unstable', 'tablet', 'tablet-unstable-v2.xml')
kbgrab_xml = join_paths(protodir, 'unstable', 'xwayland-keyboard-grab', 'xwayland-keyboard-grab-unstable-v1.xml')
xdg_output_xml = join_paths(protodir, 'unstable', 'xdg-output', 'xdg-output-unstable-v1.xml')
dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml')
viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml')
xdg_shell_xml = join_paths(protodir, 'stable', 'xdg-shell', 'xdg-shell.xml')
drm_lease_xml = join_paths(protodir, 'staging', 'drm-lease', 'drm-lease-v1.xml')
client_header = generator(scanner,
output : '@BASENAME@-client-protocol.h',
@ -60,20 +64,24 @@ code = generator(scanner,
)
srcs += client_header.process(relative_xml)
srcs += client_header.process(pointer_xml)
srcs += client_header.process(gestures_xml)
srcs += client_header.process(tablet_xml)
srcs += client_header.process(kbgrab_xml)
srcs += client_header.process(xdg_output_xml)
srcs += client_header.process(dmabuf_xml)
srcs += client_header.process(viewporter_xml)
srcs += client_header.process(xdg_shell_xml)
srcs += client_header.process(drm_lease_xml)
srcs += code.process(relative_xml)
srcs += code.process(pointer_xml)
srcs += code.process(gestures_xml)
srcs += code.process(tablet_xml)
srcs += code.process(kbgrab_xml)
srcs += code.process(xdg_output_xml)
srcs += code.process(dmabuf_xml)
srcs += code.process(viewporter_xml)
srcs += code.process(xdg_shell_xml)
srcs += code.process(drm_lease_xml)
xwayland_glamor = []
eglstream_srcs = []
@ -113,6 +121,10 @@ if build_glx
wayland_inc += glx_inc
endif
if libdrm_dep.found()
xwayland_dep += libdrm_dep
endif
xwayland_server = executable(
'Xwayland',
srcs,
@ -137,6 +149,8 @@ xwayland_server = executable(
)
xwayland_data = configuration_data()
xwayland_data.set('prefix', get_option('prefix'))
xwayland_data.set('exec_prefix', '${prefix}')
xwayland_data.set('PACKAGE_VERSION', meson.project_version())
xwayland_data.set('xwayland_path', xwayland_path)
xwayland_data.set('have_glamor', build_glamor ? 'true' : 'false')

View File

@ -54,9 +54,11 @@ expand_source_and_mask(CursorPtr cursor, CARD32 *data)
p = data;
fg = ((cursor->foreRed & 0xff00) << 8) |
(cursor->foreGreen & 0xff00) | (cursor->foreGreen >> 8);
(cursor->foreGreen & 0xff00) |
(cursor->foreBlue >> 8);
bg = ((cursor->backRed & 0xff00) << 8) |
(cursor->backGreen & 0xff00) | (cursor->backGreen >> 8);
(cursor->backGreen & 0xff00) |
(cursor->backBlue >> 8);
stride = BitmapBytePad(bits->width);
for (y = 0; y < bits->height; y++)
for (x = 0; x < bits->width; x++) {
@ -111,15 +113,6 @@ xwl_unrealize_cursor(DeviceIntPtr device, ScreenPtr screen, CursorPtr cursor)
return xwl_shm_destroy_pixmap(pixmap);
}
static void
clear_cursor_frame_callback(struct xwl_cursor *xwl_cursor)
{
if (xwl_cursor->frame_cb) {
wl_callback_destroy (xwl_cursor->frame_cb);
xwl_cursor->frame_cb = NULL;
}
}
static void
frame_callback(void *data,
struct wl_callback *callback,
@ -127,7 +120,7 @@ frame_callback(void *data,
{
struct xwl_cursor *xwl_cursor = data;
clear_cursor_frame_callback(xwl_cursor);
xwl_cursor_clear_frame_cb(xwl_cursor);
if (xwl_cursor->needs_update) {
xwl_cursor->needs_update = FALSE;
xwl_cursor->update_proc(xwl_cursor);
@ -162,8 +155,15 @@ static void
xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
struct xwl_cursor *xwl_cursor, PixmapPtr pixmap)
{
wl_surface_attach(xwl_cursor->surface,
xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0);
struct wl_buffer *buffer;
buffer = xwl_shm_pixmap_get_wl_buffer(pixmap);
if (!buffer) {
ErrorF("cursor: Error getting buffer\n");
return;
}
wl_surface_attach(xwl_cursor->surface, buffer, 0, 0);
xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0,
xwl_seat->x_cursor->bits->width,
xwl_seat->x_cursor->bits->height);
@ -180,6 +180,18 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
wl_surface_commit(xwl_cursor->surface);
}
Bool
xwl_cursor_clear_frame_cb(struct xwl_cursor *xwl_cursor)
{
if (xwl_cursor->frame_cb) {
wl_callback_destroy(xwl_cursor->frame_cb);
xwl_cursor->frame_cb = NULL;
return TRUE;
}
return FALSE;
}
void
xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
{
@ -193,7 +205,7 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
if (!xwl_seat->x_cursor) {
wl_pointer_set_cursor(xwl_seat->wl_pointer,
xwl_seat->pointer_enter_serial, NULL, 0, 0);
clear_cursor_frame_callback(xwl_cursor);
xwl_cursor_clear_frame_cb(xwl_cursor);
xwl_cursor->needs_update = FALSE;
return;
}
@ -231,7 +243,7 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
xwl_tablet_tool->proximity_in_serial,
NULL, 0, 0);
clear_cursor_frame_callback(xwl_cursor);
xwl_cursor_clear_frame_cb(xwl_cursor);
xwl_cursor->needs_update = FALSE;
return;
}
@ -257,8 +269,15 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
}
void
xwl_cursor_release(struct xwl_cursor *xwl_cursor)
{
wl_surface_destroy(xwl_cursor->surface);
xwl_cursor_clear_frame_cb(xwl_cursor);
}
static void
xwl_seat_update_cursor(struct xwl_seat *xwl_seat)
xwl_seat_update_all_cursors(struct xwl_seat *xwl_seat)
{
struct xwl_tablet_tool *xwl_tablet_tool;
@ -278,7 +297,7 @@ xwl_seat_update_cursor_visibility(struct xwl_seat *xwl_seat)
{
xwl_seat->x_cursor = xwl_seat->pending_x_cursor;
xwl_seat_cursor_visibility_changed(xwl_seat);
xwl_seat_update_cursor(xwl_seat);
xwl_seat_update_all_cursors(xwl_seat);
}
static void
@ -332,7 +351,7 @@ xwl_set_cursor(DeviceIntPtr device,
/* Cursor remains shown or hidden, apply the change immediately */
xwl_set_cursor_free_timer(xwl_seat);
xwl_seat->x_cursor = cursor;
xwl_seat_update_cursor(xwl_seat);
xwl_seat_update_all_cursors(xwl_seat);
return;
}

View File

@ -31,6 +31,8 @@
#include <xwayland-types.h>
#include <xwayland-input.h>
Bool xwl_cursor_clear_frame_cb(struct xwl_cursor *xwl_cursor);
void xwl_cursor_release(struct xwl_cursor *xwl_cursor);
void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool);
void xwl_seat_set_cursor(struct xwl_seat *xwl_seat);
Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen);

View File

@ -1,8 +1,6 @@
/* Copied from hw/xfree86/modes/xf86cvt.c into xwayland DDX and
* changed to generate an RRMode */
/*
* Copyright 2005-2006 Luc Verhaegen.
* Copyright © 2021 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"),
@ -23,284 +21,38 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* The reason for having this function in a file of its own is
* so that ../utils/cvt/cvt can link to it, and that xf86CVTMode
* code is shared directly.
*/
#include <xwayland-config.h>
#include <string.h>
#include <randrstr.h>
#include <libxcvt/libxcvt.h>
#include "xwayland-cvt.h"
/*
* Generate a CVT standard mode from HDisplay, VDisplay and VRefresh.
*
* These calculations are stolen from the CVT calculation spreadsheet written
* by Graham Loveridge. He seems to be claiming no copyright and there seems to
* be no license attached to this. He apparently just wants to see his name
* mentioned.
*
* This file can be found at http://www.vesa.org/Public/CVT/CVTd6r1.xls
*
* Comments and structure corresponds to the comments and structure of the xls.
* This should ease importing of future changes to the standard (not very
* likely though).
*
* About margins; i'm sure that they are to be the bit between HDisplay and
* HBlankStart, HBlankEnd and HTotal, VDisplay and VBlankStart, VBlankEnd and
* VTotal, where the overscan colour is shown. FB seems to call _all_ blanking
* outside sync "margin" for some reason. Since we prefer seeing proper
* blanking instead of the overscan colour, and since the Crtc* values will
* probably get altered after us, we will disable margins altogether. With
* these calculations, Margins will plainly expand H/VDisplay, and we don't
* want that. -- libv
*
*/
RRModePtr
xwayland_cvt(int HDisplay, int VDisplay, float VRefresh, Bool Reduced,
Bool Interlaced)
xwayland_cvt(int hdisplay, int vdisplay, float vrefresh, Bool reduced,
Bool interlaced)
{
/* 1) top/bottom margin size (% of height) - default: 1.8 */
#define CVT_MARGIN_PERCENTAGE 1.8
/* 2) character cell horizontal granularity (pixels) - default 8 */
#define CVT_H_GRANULARITY 8
/* 4) Minimum vertical porch (lines) - default 3 */
#define CVT_MIN_V_PORCH 3
/* 4) Minimum number of vertical back porch lines - default 6 */
#define CVT_MIN_V_BPORCH 6
/* Pixel Clock step (kHz) */
#define CVT_CLOCK_STEP 250
Bool Margins = FALSE;
float VFieldRate, HPeriod;
int HDisplayRnd, HMargin;
int VDisplayRnd, VMargin, VSync;
float Interlace; /* Please rename this */
struct libxcvt_mode_info *libxcvt_mode_info;
char name[128];
xRRModeInfo modeinfo;
libxcvt_mode_info =
libxcvt_gen_mode_info(hdisplay, vdisplay, vrefresh, reduced, interlaced);
memset(&modeinfo, 0, sizeof modeinfo);
modeinfo.width = libxcvt_mode_info->hdisplay;
modeinfo.height = libxcvt_mode_info->vdisplay;
modeinfo.dotClock = libxcvt_mode_info->dot_clock * 1000.0;
modeinfo.hSyncStart = libxcvt_mode_info->hsync_start;
modeinfo.hSyncEnd = libxcvt_mode_info->hsync_end;
modeinfo.hTotal = libxcvt_mode_info->htotal;
modeinfo.vSyncStart = libxcvt_mode_info->vsync_start;
modeinfo.vSyncEnd = libxcvt_mode_info->vsync_end;
modeinfo.vTotal = libxcvt_mode_info->vtotal;
modeinfo.modeFlags = libxcvt_mode_info->mode_flags;
/* CVT default is 60.0Hz */
if (!VRefresh)
VRefresh = 60.0;
/* 1. Required field rate */
if (Interlaced)
VFieldRate = VRefresh * 2;
else
VFieldRate = VRefresh;
/* 2. Horizontal pixels */
HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY);
/* 3. Determine left and right borders */
if (Margins) {
/* right margin is actually exactly the same as left */
HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
HMargin -= HMargin % CVT_H_GRANULARITY;
}
else
HMargin = 0;
/* 4. Find total active pixels */
modeinfo.width = HDisplayRnd + 2 * HMargin;
/* 5. Find number of lines per field */
if (Interlaced)
VDisplayRnd = VDisplay / 2;
else
VDisplayRnd = VDisplay;
/* 6. Find top and bottom margins */
/* nope. */
if (Margins)
/* top and bottom margins are equal again. */
VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
else
VMargin = 0;
modeinfo.height = VDisplay + 2 * VMargin;
/* 7. Interlace */
if (Interlaced)
Interlace = 0.5;
else
Interlace = 0.0;
/* Determine VSync Width from aspect ratio */
if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay))
VSync = 4;
else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay))
VSync = 5;
else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay))
VSync = 6;
else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay))
VSync = 7;
else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay))
VSync = 7;
else /* Custom */
VSync = 10;
if (!Reduced) { /* simplified GTF calculation */
/* 4) Minimum time of vertical sync + back porch interval (µs)
* default 550.0 */
#define CVT_MIN_VSYNC_BP 550.0
/* 3) Nominal HSync width (% of line period) - default 8 */
#define CVT_HSYNC_PERCENTAGE 8
float HBlankPercentage;
int VSyncAndBackPorch, VBackPorch;
int HBlank;
/* 8. Estimated Horizontal period */
HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) /
(VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace);
/* 9. Find number of lines in sync + backporch */
if (((int) (CVT_MIN_VSYNC_BP / HPeriod) + 1) <
(VSync + CVT_MIN_V_PORCH))
VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH;
else
VSyncAndBackPorch = (int) (CVT_MIN_VSYNC_BP / HPeriod) + 1;
/* 10. Find number of lines in back porch */
VBackPorch = VSyncAndBackPorch - VSync;
(void) VBackPorch;
/* 11. Find total number of lines in vertical field */
modeinfo.vTotal =
VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace +
CVT_MIN_V_PORCH;
/* 5) Definition of Horizontal blanking time limitation */
/* Gradient (%/kHz) - default 600 */
#define CVT_M_FACTOR 600
/* Offset (%) - default 40 */
#define CVT_C_FACTOR 40
/* Blanking time scaling factor - default 128 */
#define CVT_K_FACTOR 128
/* Scaling factor weighting - default 20 */
#define CVT_J_FACTOR 20
#define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256
#define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
CVT_J_FACTOR
/* 12. Find ideal blanking duty cycle from formula */
HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod / 1000.0;
/* 13. Blanking time */
if (HBlankPercentage < 20)
HBlankPercentage = 20;
HBlank = modeinfo.width * HBlankPercentage / (100.0 - HBlankPercentage);
HBlank -= HBlank % (2 * CVT_H_GRANULARITY);
/* 14. Find total number of pixels in a line. */
modeinfo.hTotal = modeinfo.width + HBlank;
/* Fill in HSync values */
modeinfo.hSyncEnd = modeinfo.width + HBlank / 2;
modeinfo.hSyncStart = modeinfo.hSyncEnd -
(modeinfo.hTotal * CVT_HSYNC_PERCENTAGE) / 100;
modeinfo.hSyncStart += CVT_H_GRANULARITY -
modeinfo.hSyncStart % CVT_H_GRANULARITY;
/* Fill in VSync values */
modeinfo.vSyncStart = modeinfo.height + CVT_MIN_V_PORCH;
modeinfo.vSyncEnd = modeinfo.vSyncStart + VSync;
}
else { /* Reduced blanking */
/* Minimum vertical blanking interval time (µs) - default 460 */
#define CVT_RB_MIN_VBLANK 460.0
/* Fixed number of clocks for horizontal sync */
#define CVT_RB_H_SYNC 32.0
/* Fixed number of clocks for horizontal blanking */
#define CVT_RB_H_BLANK 160.0
/* Fixed number of lines for vertical front porch - default 3 */
#define CVT_RB_VFPORCH 3
int VBILines;
/* 8. Estimate Horizontal period. */
HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) /
(VDisplayRnd + 2 * VMargin);
/* 9. Find number of lines in vertical blanking */
VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1;
/* 10. Check if vertical blanking is sufficient */
if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH))
VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH;
/* 11. Find total number of lines in vertical field */
modeinfo.vTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines;
/* 12. Find total number of pixels in a line */
modeinfo.hTotal = modeinfo.width + CVT_RB_H_BLANK;
/* Fill in HSync values */
modeinfo.hSyncEnd = modeinfo.width + CVT_RB_H_BLANK / 2;
modeinfo.hSyncStart = modeinfo.hSyncEnd - CVT_RB_H_SYNC;
/* Fill in VSync values */
modeinfo.vSyncStart = modeinfo.height + CVT_RB_VFPORCH;
modeinfo.vSyncEnd = modeinfo.vSyncStart + VSync;
}
/* 15/13. Find pixel clock frequency (kHz for xf86) */
modeinfo.dotClock = modeinfo.hTotal * 1000.0 / HPeriod;
modeinfo.dotClock -= modeinfo.dotClock % CVT_CLOCK_STEP;
modeinfo.dotClock *= 1000.0;
#if 0
/* 16/14. Find actual Horizontal Frequency (kHz) */
modeinfo.hSync = ((float) modeinfo.dotClock) / ((float) modeinfo.hTotal);
#endif
#if 0
/* 17/15. Find actual Field rate */
modeinfo.vRefresh = (1000.0 * ((float) modeinfo.dotClock)) /
((float) (modeinfo.hTotal * modeinfo.vTotal));
#endif
/* 18/16. Find actual vertical frame frequency */
/* ignore - just set the mode flag for interlaced */
if (Interlaced)
modeinfo.vTotal *= 2;
if (Reduced)
modeinfo.modeFlags |= RR_HSyncPositive | RR_VSyncNegative;
else
modeinfo.modeFlags |= RR_HSyncNegative | RR_VSyncPositive;
if (Interlaced)
modeinfo.modeFlags |= RR_Interlace;
/* FWXGA hack adapted from hw/xfree86/modes/xf86EdidModes.c, because you can't say 1366 */
if (HDisplay == 1366 && VDisplay == 768) {
modeinfo.width = 1366;
modeinfo.hSyncStart--;
modeinfo.hSyncEnd--;
}
free(libxcvt_mode_info);
snprintf(name, sizeof name, "%dx%d",
modeinfo.width, modeinfo.height);

View File

@ -0,0 +1,440 @@
/*
* Copyright © 2020 Drew Devault
* Copyright © 2021 Xaver Hugl
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that 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.
*/
#include <xwayland-config.h>
#ifdef WITH_LIBDRM
#include <xf86drm.h>
#include <xf86drmMode.h>
#endif
#include "xwayland-drm-lease.h"
#include "xwayland-screen.h"
#include "xwayland-output.h"
static void
drm_lease_handle_lease_fd(void *data,
struct wp_drm_lease_v1 *wp_drm_lease_v1,
int32_t lease_fd)
{
struct xwl_drm_lease *lease = (struct xwl_drm_lease *)data;
lease->fd = lease_fd;
AttendClient(lease->client);
}
static void
drm_lease_handle_finished(void *data,
struct wp_drm_lease_v1 *wp_drm_lease_v1)
{
struct xwl_drm_lease *lease = (struct xwl_drm_lease *)data;
struct xwl_output *output;
int i;
if (lease->fd >= 0) {
RRTerminateLease(lease->rrLease);
} else {
AttendClient(lease->client);
for (i = 0; i < lease->rrLease->numOutputs; ++i) {
output = lease->rrLease->outputs[i]->devPrivate;
output->lease = NULL;
}
}
}
static struct wp_drm_lease_v1_listener drm_lease_listener = {
.lease_fd = drm_lease_handle_lease_fd,
.finished = drm_lease_handle_finished,
};
void
xwl_randr_get_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr *rrLease, int *fd)
{
struct xwl_screen *xwl_screen;
struct xwl_drm_lease *lease;
xwl_screen = xwl_screen_get(screen);
xorg_list_for_each_entry(lease, &xwl_screen->drm_leases, link) {
if (lease->client == client) {
*rrLease = lease->rrLease;
*fd = lease->fd;
if (lease->fd < 0)
xorg_list_del(&lease->link);
return;
}
}
*rrLease = NULL;
*fd = -1;
}
int
xwl_randr_request_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr rrLease)
{
struct xwl_screen *xwl_screen;
struct wp_drm_lease_request_v1 *req;
struct xwl_drm_lease *lease_private;
struct xwl_drm_lease_device *lease_device = NULL;
struct xwl_drm_lease_device *device_data;
struct xwl_output *output;
int i;
xwl_screen = xwl_screen_get(screen);
if (xorg_list_is_empty(&xwl_screen->drm_lease_devices)) {
ErrorF("Attempted to create DRM lease without wp_drm_lease_device_v1\n");
return BadMatch;
}
xorg_list_for_each_entry(device_data, &xwl_screen->drm_lease_devices, link) {
Bool connectors_of_device = FALSE;
for (i = 0; i < rrLease->numOutputs; ++i) {
output = rrLease->outputs[i]->devPrivate;
if (output->lease_device == device_data) {
connectors_of_device = TRUE;
break;
}
}
if (connectors_of_device) {
if (lease_device != NULL) {
ErrorF("Attempted to create DRM lease from multiple devices\n");
return BadValue;
}
lease_device = device_data;
}
}
for (i = 0; i < rrLease->numOutputs; ++i) {
output = rrLease->outputs[i]->devPrivate;
if (!output || !output->lease_connector || output->lease) {
return BadValue;
}
}
req = wp_drm_lease_device_v1_create_lease_request(
lease_device->drm_lease_device);
lease_private = calloc(1, sizeof(struct xwl_drm_lease));
for (i = 0; i < rrLease->numOutputs; ++i) {
output = rrLease->outputs[i]->devPrivate;
output->lease = lease_private;
wp_drm_lease_request_v1_request_connector(req, output->lease_connector);
}
lease_private->fd = -1;
lease_private->lease = wp_drm_lease_request_v1_submit(req);
lease_private->rrLease = rrLease;
lease_private->client = client;
rrLease->devPrivate = lease_private;
wp_drm_lease_v1_add_listener(lease_private->lease,
&drm_lease_listener, lease_private);
xorg_list_add(&lease_private->link, &xwl_screen->drm_leases);
ResetCurrentRequest(client);
client->sequence--;
IgnoreClient(client);
return Success;
}
void
xwl_randr_terminate_lease(ScreenPtr screen, RRLeasePtr lease)
{
struct xwl_drm_lease *lease_private = lease->devPrivate;
if (lease_private) {
xorg_list_del(&lease_private->link);
if (lease_private->fd >= 0)
close(lease_private->fd);
wp_drm_lease_v1_destroy(lease_private->lease);
free(lease_private);
lease->devPrivate = NULL;
}
RRLeaseTerminated(lease);
}
static void
lease_connector_handle_name(void *data,
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1,
const char *name)
{
/* This space is deliberately left blank */
}
static void
lease_connector_handle_description(void *data,
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1,
const char *description)
{
/* This space is deliberately left blank */
}
static RRModePtr *
xwl_get_rrmodes_from_connector_id(int drm, int32_t connector_id, int *nmode, int *npref)
{
#ifdef WITH_LIBDRM
drmModeConnectorPtr conn;
drmModeModeInfoPtr kmode;
RRModePtr *rrmodes;
int pref, i;
*nmode = *npref = 0;
conn = drmModeGetConnectorCurrent(drm, connector_id);
if (!conn) {
ErrorF("drmModeGetConnector for connector %d failed\n", connector_id);
return NULL;
}
rrmodes = xallocarray(conn->count_modes, sizeof(RRModePtr));
if (!rrmodes) {
ErrorF("Failed to allocate connector modes\n");
drmModeFreeConnector(conn);
return NULL;
}
/* This spaghetti brought to you courtesey of xf86RandrR12.c
* It adds preferred modes first, then non-preferred modes */
for (pref = 1; pref >= 0; pref--) {
for (i = 0; i < conn->count_modes; ++i) {
kmode = &conn->modes[i];
if ((pref != 0) == ((kmode->type & DRM_MODE_TYPE_PREFERRED) != 0)) {
xRRModeInfo modeInfo;
RRModePtr rrmode;
modeInfo.nameLength = strlen(kmode->name);
modeInfo.width = kmode->hdisplay;
modeInfo.dotClock = kmode->clock * 1000;
modeInfo.hSyncStart = kmode->hsync_start;
modeInfo.hSyncEnd = kmode->hsync_end;
modeInfo.hTotal = kmode->htotal;
modeInfo.hSkew = kmode->hskew;
modeInfo.height = kmode->vdisplay;
modeInfo.vSyncStart = kmode->vsync_start;
modeInfo.vSyncEnd = kmode->vsync_end;
modeInfo.vTotal = kmode->vtotal;
modeInfo.modeFlags = kmode->flags;
rrmode = RRModeGet(&modeInfo, kmode->name);
if (rrmode) {
rrmodes[*nmode] = rrmode;
*nmode = *nmode + 1;
*npref = *npref + pref;
}
}
}
}
/* workaround: there could be no preferred mode that got added */
if (*nmode > 0 && *npref == 0)
*npref = 1;
drmModeFreeConnector(conn);
return rrmodes;
#else
*nmode = *npref = 0;
return NULL;
#endif
}
static void
lease_connector_handle_connector_id(void *data,
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1,
uint32_t connector_id)
{
struct xwl_output *output;
Atom name;
INT32 value;
int err;
int nmode, npref;
RRModePtr *rrmodes;
value = connector_id;
output = (struct xwl_output *)data;
name = MakeAtom("CONNECTOR_ID", 12, TRUE);
if (name != BAD_RESOURCE) {
err = RRConfigureOutputProperty(output->randr_output, name,
FALSE, FALSE, TRUE,
1, &value);
if (err != 0) {
ErrorF("RRConfigureOutputProperty error, %d\n", err);
return;
}
err = RRChangeOutputProperty(output->randr_output, name,
XA_INTEGER, 32, PropModeReplace, 1,
&value, FALSE, FALSE);
if (err != 0) {
ErrorF("RRChangeOutputProperty error, %d\n", err);
return;
}
}
rrmodes = xwl_get_rrmodes_from_connector_id(output->lease_device->drm_read_only_fd,
connector_id, &nmode, &npref);
if (rrmodes != NULL)
RROutputSetModes(output->randr_output, rrmodes, nmode, npref);
free(rrmodes);
}
static void
lease_connector_handle_done(void *data,
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1)
{
/* This space is deliberately left blank */
}
static void
lease_connector_handle_withdrawn(void *data,
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1)
{
xwl_output_remove(data);
}
static const struct wp_drm_lease_connector_v1_listener lease_connector_listener = {
.name = lease_connector_handle_name,
.description = lease_connector_handle_description,
.connector_id = lease_connector_handle_connector_id,
.withdrawn = lease_connector_handle_withdrawn,
.done = lease_connector_handle_done,
};
static void
drm_lease_device_handle_drm_fd(void *data,
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1,
int fd)
{
((struct xwl_drm_lease_device *)data)->drm_read_only_fd = fd;
}
static void
drm_lease_device_handle_connector(void *data,
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1,
struct wp_drm_lease_connector_v1 *connector)
{
struct xwl_drm_lease_device *lease_device = data;
struct xwl_output *xwl_output;
char name[256];
xwl_output = calloc(1, sizeof *xwl_output);
if (xwl_output == NULL) {
ErrorF("%s ENOMEM\n", __func__);
return;
}
snprintf(name, sizeof name, "XWAYLAND%d", xwl_get_next_output_serial());
xwl_output->lease_device = lease_device;
xwl_output->xwl_screen = lease_device->xwl_screen;
xwl_output->lease_connector = connector;
xwl_output->randr_crtc = RRCrtcCreate(lease_device->xwl_screen->screen, xwl_output);
if (!xwl_output->randr_crtc) {
ErrorF("Failed creating RandR CRTC\n");
goto err;
}
RRCrtcSetRotations(xwl_output->randr_crtc, ALL_ROTATIONS);
xwl_output->randr_output = RROutputCreate(lease_device->xwl_screen->screen,
name, strlen(name), xwl_output);
if (!xwl_output->randr_output) {
ErrorF("Failed creating RandR Output\n");
goto err;
}
RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
RROutputSetConnection(xwl_output->randr_output, RR_Connected);
RROutputSetNonDesktop(xwl_output->randr_output, TRUE);
xwl_output->randr_output->devPrivate = xwl_output;
wp_drm_lease_connector_v1_add_listener(connector,
&lease_connector_listener,
xwl_output);
xorg_list_append(&xwl_output->link, &lease_device->xwl_screen->output_list);
return;
err:
if (xwl_output->randr_crtc)
RRCrtcDestroy(xwl_output->randr_crtc);
free(xwl_output);
}
static void
drm_lease_device_handle_released(void *data,
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1)
{
struct xwl_drm_lease_device *lease_device = data;
xwl_screen_destroy_drm_lease_device(lease_device->xwl_screen, wp_drm_lease_device_v1);
}
static void
drm_lease_device_handle_done(void *data,
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1)
{
/* This space is deliberately left blank */
}
static const struct wp_drm_lease_device_v1_listener drm_lease_device_listener = {
.drm_fd = drm_lease_device_handle_drm_fd,
.connector = drm_lease_device_handle_connector,
.released = drm_lease_device_handle_released,
.done = drm_lease_device_handle_done,
};
void
xwl_screen_add_drm_lease_device(struct xwl_screen *xwl_screen, uint32_t id)
{
struct wp_drm_lease_device_v1 *lease_device = wl_registry_bind(
xwl_screen->registry, id, &wp_drm_lease_device_v1_interface, 1);
struct xwl_drm_lease_device *device_data = malloc(sizeof(struct xwl_drm_lease_device));
device_data->drm_lease_device = lease_device;
device_data->xwl_screen = xwl_screen;
device_data->drm_read_only_fd = -1;
device_data->id = id;
xorg_list_add(&device_data->link, &xwl_screen->drm_lease_devices);
wp_drm_lease_device_v1_add_listener(lease_device,
&drm_lease_device_listener,
device_data);
}
void
xwl_screen_destroy_drm_lease_device(struct xwl_screen *xwl_screen,
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1)
{
struct xwl_drm_lease_device *device_data;
xorg_list_for_each_entry(device_data, &xwl_screen->drm_lease_devices, link) {
if (device_data->drm_lease_device == wp_drm_lease_device_v1) {
wp_drm_lease_device_v1_destroy(wp_drm_lease_device_v1);
xorg_list_del(&device_data->link);
if (device_data->drm_read_only_fd >= 0)
close(device_data->drm_read_only_fd);
free(device_data);
return;
}
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright © 2020 Drew Devault
* Copyright © 2021 Xaver Hugl
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that 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.
*/
#ifndef XWAYLAND_DRM_LEASE_H
#define XWAYLAND_DRM_LEASE_H
#include <X11/Xatom.h>
#include <randrstr.h>
#include "xwayland-types.h"
#include "list.h"
#include "drm-lease-v1-client-protocol.h"
struct xwl_drm_lease_device {
struct xorg_list link;
struct wp_drm_lease_device_v1 *drm_lease_device;
int drm_read_only_fd;
struct xwl_screen *xwl_screen;
uint32_t id;
};
struct xwl_queued_drm_lease_device {
struct xorg_list link;
uint32_t id;
};
struct xwl_drm_lease {
struct xorg_list link;
struct wp_drm_lease_v1 *lease;
RRLeasePtr rrLease;
ClientPtr client;
int fd;
};
int xwl_randr_request_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr rrLease);
void xwl_randr_get_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr *rrLease, int *fd);
void xwl_randr_terminate_lease(ScreenPtr screen, RRLeasePtr lease);
void xwl_screen_add_drm_lease_device(struct xwl_screen *xwl_screen, uint32_t id);
void xwl_screen_destroy_drm_lease_device(struct xwl_screen *xwl_screen,
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1);
#endif /* XWAYLAND_DRM_LEASE_H */

View File

@ -33,10 +33,13 @@
#define EGL_NO_X11
#include <glamor_egl.h>
#include <glamor.h>
#include <glamor_priv.h>
#include <glamor_transform.h>
#include <glamor_transfer.h>
#include <xf86drm.h>
#include <dri3.h>
#include <drm_fourcc.h>
#include <epoxy/egl.h>
@ -47,18 +50,7 @@
#include "wayland-eglstream-client-protocol.h"
#include "wayland-eglstream-controller-client-protocol.h"
struct xwl_eglstream_pending_stream {
PixmapPtr pixmap;
WindowPtr window;
struct xwl_pixmap *xwl_pixmap;
struct wl_callback *cb;
Bool is_valid;
struct xorg_list link;
};
#include "linux-dmabuf-unstable-v1-client-protocol.h"
struct xwl_eglstream_private {
EGLDeviceEXT egl_device;
@ -68,11 +60,8 @@ struct xwl_eglstream_private {
EGLConfig config;
SetWindowPixmapProcPtr SetWindowPixmap;
struct xorg_list pending_streams;
Bool have_egl_damage;
Bool have_egl_stream_flush;
GLint blit_prog;
GLuint blit_vao;
@ -80,16 +69,28 @@ struct xwl_eglstream_private {
GLuint blit_is_rgba_pos;
};
struct xwl_pixmap {
struct wl_buffer *buffer;
struct xwl_screen *xwl_screen;
enum xwl_pixmap_type {
XWL_PIXMAP_EGLSTREAM, /* Pixmaps created by glamor. */
XWL_PIXMAP_DMA_BUF, /* Pixmaps allocated through DRI3. */
};
struct xwl_pixmap {
enum xwl_pixmap_type type;
/* add any new <= 4-byte member here to avoid holes on 64-bit */
struct xwl_screen *xwl_screen;
struct wl_buffer *buffer;
struct wl_callback *pending_cb;
Bool wait_for_buffer_release;
/* XWL_PIXMAP_EGLSTREAM. */
EGLStreamKHR stream;
EGLSurface surface;
/* XWL_PIXMAP_DMA_BUF. */
EGLImage image;
};
static DevPrivateKeyRec xwl_eglstream_private_key;
static DevPrivateKeyRec xwl_eglstream_window_private_key;
static inline struct xwl_eglstream_private *
xwl_eglstream_get(struct xwl_screen *xwl_screen)
@ -98,52 +99,6 @@ xwl_eglstream_get(struct xwl_screen *xwl_screen)
&xwl_eglstream_private_key);
}
static inline struct xwl_eglstream_pending_stream *
xwl_eglstream_window_get_pending(WindowPtr window)
{
return dixLookupPrivate(&window->devPrivates,
&xwl_eglstream_window_private_key);
}
static inline void
xwl_eglstream_window_set_pending(WindowPtr window,
struct xwl_eglstream_pending_stream *stream)
{
dixSetPrivate(&window->devPrivates,
&xwl_eglstream_window_private_key, stream);
}
static GLint
xwl_eglstream_compile_glsl_prog(GLenum type, const char *source)
{
GLint ok;
GLint prog;
prog = glCreateShader(type);
glShaderSource(prog, 1, (const GLchar **) &source, NULL);
glCompileShader(prog);
glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
if (!ok) {
GLchar *info;
GLint size;
glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
info = malloc(size);
if (info) {
glGetShaderInfoLog(prog, size, NULL, info);
ErrorF("Failed to compile %s: %s\n",
type == GL_FRAGMENT_SHADER ? "FS" : "VS", info);
ErrorF("Program source:\n%s", source);
free(info);
}
else
ErrorF("Failed to get shader compilation info.\n");
FatalError("GLSL compile failure\n");
}
return prog;
}
static GLuint
xwl_eglstream_build_glsl_prog(GLuint vs, GLuint fs)
{
@ -273,7 +228,7 @@ xwl_glamor_egl_device_has_egl_extensions(void *device,
}
static void
xwl_eglstream_unref_pixmap_stream(struct xwl_pixmap *xwl_pixmap)
xwl_eglstream_destroy_pixmap_stream(struct xwl_pixmap *xwl_pixmap)
{
struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen;
@ -289,31 +244,29 @@ xwl_eglstream_unref_pixmap_stream(struct xwl_pixmap *xwl_pixmap)
xwl_screen->egl_context);
}
if (xwl_pixmap->surface)
if (xwl_pixmap->surface != EGL_NO_SURFACE)
eglDestroySurface(xwl_screen->egl_display, xwl_pixmap->surface);
eglDestroyStreamKHR(xwl_screen->egl_display, xwl_pixmap->stream);
if (xwl_pixmap->stream != EGL_NO_STREAM_KHR)
eglDestroyStreamKHR(xwl_screen->egl_display, xwl_pixmap->stream);
if (xwl_pixmap->buffer)
wl_buffer_destroy(xwl_pixmap->buffer);
if (xwl_pixmap->image != EGL_NO_IMAGE_KHR)
eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
wl_buffer_destroy(xwl_pixmap->buffer);
free(xwl_pixmap);
}
static void
xwl_glamor_eglstream_del_pending_stream_cb(struct xwl_pixmap *xwl_pixmap)
xwl_eglstream_destroy_pending_cb(PixmapPtr pixmap)
{
struct xwl_eglstream_private *xwl_eglstream =
xwl_eglstream_get(xwl_pixmap->xwl_screen);
struct xwl_eglstream_pending_stream *pending;
struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
xorg_list_for_each_entry(pending,
&xwl_eglstream->pending_streams, link) {
if (pending->xwl_pixmap == xwl_pixmap) {
wl_callback_destroy(pending->cb);
xwl_eglstream_window_set_pending(pending->window, NULL);
xorg_list_del(&pending->link);
free(pending);
break;
}
if (xwl_pixmap && xwl_pixmap->pending_cb) {
wl_callback_destroy(xwl_pixmap->pending_cb);
xwl_pixmap->pending_cb = NULL;
}
}
@ -323,9 +276,9 @@ xwl_glamor_eglstream_destroy_pixmap(PixmapPtr pixmap)
struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
if (xwl_pixmap && pixmap->refcnt == 1) {
xwl_glamor_eglstream_del_pending_stream_cb(xwl_pixmap);
xwl_eglstream_destroy_pending_cb(pixmap);
xwl_eglstream_destroy_pixmap_stream(xwl_pixmap);
xwl_pixmap_del_buffer_release_cb(pixmap);
xwl_eglstream_unref_pixmap_stream(xwl_pixmap);
}
return glamor_destroy_pixmap(pixmap);
}
@ -333,160 +286,142 @@ xwl_glamor_eglstream_destroy_pixmap(PixmapPtr pixmap)
static struct wl_buffer *
xwl_glamor_eglstream_get_wl_buffer_for_pixmap(PixmapPtr pixmap)
{
return xwl_pixmap_get(pixmap)->buffer;
struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
if (!xwl_pixmap)
return NULL;
return xwl_pixmap->buffer;
}
static void
xwl_eglstream_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
static const char *
xwl_eglstream_get_error_str(EGLint error)
{
struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
struct xwl_eglstream_private *xwl_eglstream =
xwl_eglstream_get(xwl_screen);
struct xwl_eglstream_pending_stream *pending;
switch (error) {
case EGL_BAD_PARAMETER:
return "EGL_BAD_PARAMETER";
case EGL_BAD_ATTRIBUTE:
return "EGL_BAD_ATTRIBUTE";
case EGL_BAD_MATCH:
return "EGL_BAD_MATCH";
case EGL_BAD_ACCESS:
return "EGL_BAD_ACCESS";
case EGL_BAD_STATE_KHR:
return "EGL_BAD_STATE_KHR";
case EGL_BAD_STREAM_KHR:
return "EGL_BAD_STREAM_KHR";
case EGL_BAD_DISPLAY:
return "EGL_BAD_DISPLAY";
case EGL_NOT_INITIALIZED:
return "EGL_NOT_INITIALIZED";
default:
return "Unknown error";
}
}
pending = xwl_eglstream_window_get_pending(window);
if (pending) {
/* The pixmap for this window has changed before the compositor
* finished attaching the consumer for the window's pixmap's original
* eglstream. A producer can no longer be attached, so the stream's
* useless
*/
pending->is_valid = FALSE;
static const char *
xwl_eglstream_get_stream_state_str(EGLint state)
{
switch (state) {
case EGL_STREAM_STATE_CREATED_KHR:
return "EGL_STREAM_STATE_CREATED_KHR";
case EGL_STREAM_STATE_CONNECTING_KHR:
return "EGL_STREAM_STATE_CONNECTING_KHR";
case EGL_STREAM_STATE_EMPTY_KHR:
return "EGL_STREAM_STATE_EMPTY_KHR";
case EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR:
return "EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR";
case EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR:
return "EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR";
case EGL_STREAM_STATE_DISCONNECTED_KHR:
return "EGL_STREAM_STATE_DISCONNECTED_KHR";
default:
return "Unknown state";
}
}
static EGLint
xwl_eglstream_get_state(EGLDisplay egl_display, EGLStreamKHR egl_stream)
{
EGLint state;
eglQueryStreamKHR(egl_display, egl_stream, EGL_STREAM_STATE_KHR, &state);
if (!eglQueryStreamKHR(egl_display, egl_stream,
EGL_STREAM_STATE_KHR, &state)) {
EGLint state_error = eglGetError();
ErrorF("eglstream: Failed to query state - error 0x%X: %s\n",
state_error, xwl_eglstream_get_error_str(state_error));
return EGL_FALSE;
}
xwl_screen->screen->SetWindowPixmap = xwl_eglstream->SetWindowPixmap;
(*xwl_screen->screen->SetWindowPixmap)(window, pixmap);
xwl_eglstream->SetWindowPixmap = xwl_screen->screen->SetWindowPixmap;
xwl_screen->screen->SetWindowPixmap = xwl_eglstream_set_window_pixmap;
return state;
}
static void
xwl_eglstream_print_error(EGLDisplay egl_display,
EGLStreamKHR egl_stream, EGLint error)
{
ErrorF("eglstream: error 0x%X: %s\n", error,
xwl_eglstream_get_error_str(error));
if (error == EGL_BAD_STATE_KHR) {
EGLint state = xwl_eglstream_get_state(egl_display, egl_stream);
ErrorF("eglstream: stream state 0x%X: %s\n", state,
xwl_eglstream_get_stream_state_str(state));
}
}
/* Because we run asynchronously with our wayland compositor, it's possible
* that an X client event could cause us to begin creating a stream for a
* pixmap/window combo before the stream for the pixmap this window
* previously used has been fully initialized. An example:
*
* - Start processing X client events.
* - X window receives resize event, causing us to create a new pixmap and
* begin creating the corresponding eglstream. This pixmap is known as
* pixmap A.
* - X window receives another resize event, and again changes its current
* pixmap causing us to create another corresponding eglstream for the same
* window. This pixmap is known as pixmap B.
* - Start handling events from the wayland compositor.
*
* Since both pixmap A and B will have scheduled wl_display_sync events to
* indicate when their respective streams are connected, we will receive each
* callback in the original order the pixmaps were created. This means the
* following would happen:
*
* - Receive pixmap A's stream callback, attach its stream to the surface of
* the window that just orphaned it.
* - Receive pixmap B's stream callback, fall over and fail because the
* window's surface now incorrectly has pixmap A's stream attached to it.
*
* We work around this problem by keeping a queue of pending streams, and
* only allowing one queue entry to exist for each window. In the scenario
* listed above, this should happen:
*
* - Begin processing X events...
* - A window is resized, causing us to add an eglstream (known as eglstream
* A) waiting for its consumer to finish attachment to be added to the
* queue.
* - Resize on same window happens. We invalidate the previously pending
* stream and add another one to the pending queue (known as eglstream B).
* - Begin processing Wayland events...
* - Receive invalidated callback from compositor for eglstream A, destroy
* stream.
* - Receive callback from compositor for eglstream B, create producer.
* - Success!
*/
static void
xwl_eglstream_consumer_ready_callback(void *data,
struct wl_callback *callback,
uint32_t time)
{
struct xwl_screen *xwl_screen = data;
PixmapPtr pixmap = data;
struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen;
struct xwl_eglstream_private *xwl_eglstream =
xwl_eglstream_get(xwl_screen);
struct xwl_pixmap *xwl_pixmap;
struct xwl_eglstream_pending_stream *pending;
Bool found = FALSE;
wl_callback_destroy(callback);
xorg_list_for_each_entry(pending, &xwl_eglstream->pending_streams, link) {
if (pending->cb == callback) {
found = TRUE;
break;
}
}
assert(found);
if (!pending->is_valid) {
xwl_eglstream_unref_pixmap_stream(pending->xwl_pixmap);
goto out;
}
xwl_eglstream_destroy_pending_cb(pixmap);
xwl_glamor_egl_make_current(xwl_screen);
xwl_pixmap = pending->xwl_pixmap;
xwl_pixmap->surface = eglCreateStreamProducerSurfaceKHR(
xwl_screen->egl_display, xwl_eglstream->config,
xwl_pixmap->stream, (int[]) {
EGL_WIDTH, pending->pixmap->drawable.width,
EGL_HEIGHT, pending->pixmap->drawable.height,
EGL_WIDTH, pixmap->drawable.width,
EGL_HEIGHT, pixmap->drawable.height,
EGL_NONE
});
DebugF("eglstream: win %d completes eglstream for pixmap %p, congrats!\n",
pending->window->drawable.id, pending->pixmap);
out:
xwl_eglstream_window_set_pending(pending->window, NULL);
xorg_list_del(&pending->link);
free(pending);
if (xwl_pixmap->surface == EGL_NO_SURFACE) {
ErrorF("eglstream: Failed to create EGLSurface for pixmap\n");
xwl_eglstream_print_error(xwl_screen->egl_display,
xwl_pixmap->stream, eglGetError());
} else {
DebugF("eglstream: completes eglstream for pixmap %p, congrats!\n",
pixmap);
}
}
static const struct wl_callback_listener consumer_ready_listener = {
xwl_eglstream_consumer_ready_callback
};
static void
xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen,
WindowPtr window, PixmapPtr pixmap)
{
struct xwl_eglstream_private *xwl_eglstream =
xwl_eglstream_get(xwl_screen);
struct xwl_eglstream_pending_stream *pending_stream;
#ifdef DEBUG
if (!xwl_eglstream_window_get_pending(window))
DebugF("eglstream: win %d begins new eglstream for pixmap %p\n",
window->drawable.id, pixmap);
else
DebugF("eglstream: win %d interrupts and replaces pending eglstream for pixmap %p\n",
window->drawable.id, pixmap);
#endif
pending_stream = malloc(sizeof(*pending_stream));
pending_stream->window = window;
pending_stream->pixmap = pixmap;
pending_stream->xwl_pixmap = xwl_pixmap_get(pixmap);
pending_stream->is_valid = TRUE;
xorg_list_init(&pending_stream->link);
xorg_list_add(&pending_stream->link, &xwl_eglstream->pending_streams);
xwl_eglstream_window_set_pending(window, pending_stream);
pending_stream->cb = wl_display_sync(xwl_screen->display);
wl_callback_add_listener(pending_stream->cb, &consumer_ready_listener,
xwl_screen);
}
static void
xwl_eglstream_buffer_release_callback(void *data)
{
/* drop the reference we took in post_damage, freeing if necessary */
dixDestroyPixmap(data, 0);
PixmapPtr pixmap = data;
struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
assert(xwl_pixmap);
if (xwl_pixmap->wait_for_buffer_release) {
xwl_pixmap->wait_for_buffer_release = FALSE;
/* drop the reference we took in the ready callback, freeing if necessary */
dixDestroyPixmap(pixmap, 0);
}
}
static const struct wl_buffer_listener xwl_eglstream_buffer_release_listener = {
@ -494,8 +429,8 @@ static const struct wl_buffer_listener xwl_eglstream_buffer_release_listener = {
};
static void
xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen,
WindowPtr window, PixmapPtr pixmap)
xwl_eglstream_create_pixmap_and_stream(struct xwl_screen *xwl_screen,
WindowPtr window, PixmapPtr pixmap)
{
struct xwl_eglstream_private *xwl_eglstream =
xwl_eglstream_get(xwl_screen);
@ -504,17 +439,30 @@ xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen,
struct wl_array stream_attribs;
int stream_fd = -1;
xwl_pixmap = calloc(sizeof(*xwl_pixmap), 1);
xwl_pixmap = calloc(1, sizeof(*xwl_pixmap));
if (!xwl_pixmap)
FatalError("Not enough memory to create pixmap\n");
xwl_pixmap_set_private(pixmap, xwl_pixmap);
xwl_pixmap->type = XWL_PIXMAP_EGLSTREAM;
xwl_pixmap->image = EGL_NO_IMAGE;
xwl_glamor_egl_make_current(xwl_screen);
xwl_pixmap->wait_for_buffer_release = FALSE;
xwl_pixmap->xwl_screen = xwl_screen;
xwl_pixmap->surface = EGL_NO_SURFACE;
xwl_pixmap->stream = eglCreateStreamKHR(xwl_screen->egl_display, NULL);
if (xwl_pixmap->stream == EGL_NO_STREAM_KHR) {
ErrorF("eglstream: Couldn't create EGL stream.\n");
goto fail;
}
stream_fd = eglGetStreamFileDescriptorKHR(xwl_screen->egl_display,
xwl_pixmap->stream);
if (stream_fd == EGL_NO_FILE_DESCRIPTOR_KHR) {
ErrorF("eglstream: Couldn't get EGL stream file descriptor.\n");
goto fail;
}
wl_array_init(&stream_attribs);
xwl_pixmap->buffer =
@ -524,6 +472,10 @@ xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen,
stream_fd,
WL_EGLSTREAM_HANDLE_TYPE_FD,
&stream_attribs);
if (!xwl_pixmap->buffer) {
ErrorF("eglstream: Failed to create buffer\n");
goto fail;
}
wl_buffer_add_listener(xwl_pixmap->buffer,
&xwl_eglstream_buffer_release_listener,
@ -536,46 +488,51 @@ xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen,
wl_eglstream_controller_attach_eglstream_consumer(
xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer);
xwl_eglstream_queue_pending_stream(xwl_screen, window, pixmap);
close(stream_fd);
xwl_pixmap->pending_cb = wl_display_sync(xwl_screen->display);
wl_callback_add_listener(xwl_pixmap->pending_cb, &consumer_ready_listener,
pixmap);
fail:
if (stream_fd >= 0)
close(stream_fd);
}
static Bool
xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window)
{
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
struct xwl_eglstream_pending_stream *pending =
xwl_eglstream_window_get_pending(xwl_window->window);
PixmapPtr pixmap =
(*xwl_screen->screen->GetWindowPixmap)(xwl_window->window);
struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
if (xwl_pixmap) {
if (pending) {
if (xwl_pixmap->pending_cb) {
/* Wait for the compositor to finish connecting the consumer for
* this eglstream */
if (pending->is_valid)
return FALSE;
return FALSE;
}
/* The pixmap for this window was changed before the compositor
* finished connecting the eglstream for the window's previous
* pixmap. Begin creating a new eglstream. */
} else {
if (xwl_pixmap->surface != EGL_NO_SURFACE ||
xwl_pixmap->type == XWL_PIXMAP_DMA_BUF) {
return TRUE;
}
/* The pending stream got removed, we have a xwl_pixmap and
* yet we do not have a surface.
* So something went wrong with the surface creation, retry.
*/
xwl_eglstream_destroy_pixmap_stream(xwl_pixmap);
}
/* Glamor pixmap has no backing stream yet; begin making one and disallow
* commits until then
*/
xwl_eglstream_create_pending_stream(xwl_screen, xwl_window->window,
pixmap);
xwl_eglstream_create_pixmap_and_stream(xwl_screen, xwl_window->window,
pixmap);
return FALSE;
}
static void
static Bool
xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window,
PixmapPtr pixmap, RegionPtr region)
{
@ -589,11 +546,21 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window,
box->x2 - box->x1, box->y2 - box->y1
};
GLint saved_vao;
int status;
if (xwl_pixmap->type != XWL_PIXMAP_EGLSTREAM)
/* This can happen if a client does X11 rendering on a
* flipping OpenGL or Vulkan window. In that case, we don't
* need to do the copy below.
*/
return TRUE;
/* Unbind the framebuffer BEFORE binding the EGLSurface, otherwise we
* won't actually draw to it
*/
xwl_glamor_egl_make_current(xwl_screen);
glamor_set_alu(xwl_screen->screen, GXcopy);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (eglGetCurrentSurface(EGL_READ) != xwl_pixmap->surface ||
@ -615,22 +582,55 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window,
glUniform1i(xwl_eglstream->blit_is_rgba_pos,
pixmap->drawable.depth >= 32);
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
ErrorF("eglstream: Framebuffer incomplete 0x%X, not posting damage\n", status);
status = FALSE;
goto out;
}
/* Blit rendered image into EGLStream surface */
glDrawBuffer(GL_BACK);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
if (xwl_eglstream->have_egl_damage)
eglSwapBuffersWithDamageKHR(xwl_screen->egl_display,
xwl_pixmap->surface, egl_damage, 1);
status = eglSwapBuffersWithDamageKHR(xwl_screen->egl_display,
xwl_pixmap->surface,
egl_damage, 1);
else
eglSwapBuffers(xwl_screen->egl_display, xwl_pixmap->surface);
status = eglSwapBuffers(xwl_screen->egl_display,
xwl_pixmap->surface);
if (!status) {
ErrorF("eglstream: buffer swap failed, not posting damage\n");
goto out;
}
#ifdef EGL_NV_stream_flush
if (xwl_eglstream->have_egl_stream_flush)
/* block until stream state is updated on the compositor's side */
eglStreamFlushNV(xwl_screen->egl_display,
xwl_pixmap->stream);
#endif
if (!xwl_pixmap->wait_for_buffer_release) {
/* hang onto the pixmap until the compositor has released it */
pixmap->refcnt++;
xwl_pixmap->wait_for_buffer_release = TRUE;
}
out:
/* Restore previous state */
glBindVertexArray(saved_vao);
glBindTexture(GL_TEXTURE_2D, 0);
/* hang onto the pixmap until the compositor has released it */
pixmap->refcnt++;
return status;
}
static Bool
xwl_glamor_eglstream_check_flip(PixmapPtr pixmap)
{
return xwl_pixmap_get(pixmap)->type == XWL_PIXMAP_DMA_BUF;
}
static void
@ -675,6 +675,9 @@ xwl_glamor_eglstream_init_wl_registry(struct xwl_screen *xwl_screen,
xwl_eglstream->controller = wl_registry_bind(
wl_registry, id, &wl_eglstream_controller_interface, version);
return TRUE;
} else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0) {
xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
return TRUE;
}
/* no match */
@ -688,12 +691,14 @@ xwl_glamor_eglstream_has_wl_interfaces(struct xwl_screen *xwl_screen)
xwl_eglstream_get(xwl_screen);
if (xwl_eglstream->display == NULL) {
ErrorF("glamor: 'wl_eglstream_display' not supported\n");
LogMessageVerb(X_INFO, 3,
"glamor: 'wl_eglstream_display' not supported\n");
return FALSE;
}
if (xwl_eglstream->controller == NULL) {
ErrorF("glamor: 'wl_eglstream_controller' not supported\n");
LogMessageVerb(X_INFO, 3,
"glamor: 'wl_eglstream_controller' not supported\n");
return FALSE;
}
@ -741,8 +746,8 @@ xwl_eglstream_init_shaders(struct xwl_screen *xwl_screen)
0, 0,
};
vs = xwl_eglstream_compile_glsl_prog(GL_VERTEX_SHADER, blit_vs_src);
fs = xwl_eglstream_compile_glsl_prog(GL_FRAGMENT_SHADER, blit_fs_src);
vs = glamor_compile_glsl_prog(GL_VERTEX_SHADER, blit_vs_src);
fs = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, blit_fs_src);
xwl_eglstream->blit_prog = xwl_eglstream_build_glsl_prog(vs, fs);
glDeleteShader(vs);
@ -773,6 +778,163 @@ xwl_eglstream_init_shaders(struct xwl_screen *xwl_screen)
glGetUniformLocation(xwl_eglstream->blit_prog, "is_rgba");
}
static int
xwl_dri3_open_client(ClientPtr client,
ScreenPtr screen,
RRProviderPtr provider,
int *pfd)
{
/* Not supported with this backend. */
return BadImplementation;
}
static PixmapPtr
xwl_dri3_pixmap_from_fds(ScreenPtr screen,
CARD8 num_fds, const int *fds,
CARD16 width, CARD16 height,
const CARD32 *strides, const CARD32 *offsets,
CARD8 depth, CARD8 bpp,
uint64_t modifier)
{
PixmapPtr pixmap;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
struct xwl_pixmap *xwl_pixmap;
unsigned int texture;
EGLint image_attribs[48];
uint32_t mod_hi = modifier >> 32, mod_lo = modifier & 0xffffffff, format;
int attrib = 0, i;
struct zwp_linux_buffer_params_v1 *params;
format = wl_drm_format_for_depth(depth);
if (!xwl_glamor_is_modifier_supported(xwl_screen, format, modifier)) {
ErrorF("glamor: unsupported format modifier\n");
return NULL;
}
xwl_pixmap = calloc(1, sizeof (*xwl_pixmap));
if (!xwl_pixmap)
return NULL;
xwl_pixmap->type = XWL_PIXMAP_DMA_BUF;
xwl_pixmap->xwl_screen = xwl_screen;
xwl_pixmap->buffer = NULL;
xwl_pixmap->stream = EGL_NO_STREAM_KHR;
xwl_pixmap->surface = EGL_NO_SURFACE;
params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf);
for (i = 0; i < num_fds; i++) {
zwp_linux_buffer_params_v1_add(params, fds[i], i,
offsets[i], strides[i],
mod_hi, mod_lo);
}
xwl_pixmap->buffer =
zwp_linux_buffer_params_v1_create_immed(params, width, height,
format, 0);
zwp_linux_buffer_params_v1_destroy(params);
image_attribs[attrib++] = EGL_WIDTH;
image_attribs[attrib++] = width;
image_attribs[attrib++] = EGL_HEIGHT;
image_attribs[attrib++] = height;
image_attribs[attrib++] = EGL_LINUX_DRM_FOURCC_EXT;
image_attribs[attrib++] = drm_format_for_depth(depth, bpp);
if (num_fds > 0) {
image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_FD_EXT;
image_attribs[attrib++] = fds[0];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
image_attribs[attrib++] = offsets[0];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
image_attribs[attrib++] = strides[0];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
image_attribs[attrib++] = mod_hi;
image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
image_attribs[attrib++] = mod_lo;
}
if (num_fds > 1) {
image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_FD_EXT;
image_attribs[attrib++] = fds[1];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
image_attribs[attrib++] = offsets[1];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
image_attribs[attrib++] = strides[1];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
image_attribs[attrib++] = mod_hi;
image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
image_attribs[attrib++] = mod_lo;
}
if (num_fds > 2) {
image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_FD_EXT;
image_attribs[attrib++] = fds[2];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
image_attribs[attrib++] = offsets[2];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
image_attribs[attrib++] = strides[2];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
image_attribs[attrib++] = mod_hi;
image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
image_attribs[attrib++] = mod_lo;
}
if (num_fds > 3) {
image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_FD_EXT;
image_attribs[attrib++] = fds[3];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
image_attribs[attrib++] = offsets[3];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
image_attribs[attrib++] = strides[3];
image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
image_attribs[attrib++] = mod_hi;
image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
image_attribs[attrib++] = mod_lo;
}
image_attribs[attrib++] = EGL_NONE;
xwl_glamor_egl_make_current(xwl_screen);
/* eglCreateImageKHR will close fds */
xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT,
NULL, image_attribs);
if (xwl_pixmap->image == EGL_NO_IMAGE_KHR) {
ErrorF("eglCreateImageKHR failed!\n");
if (xwl_pixmap->buffer)
wl_buffer_destroy(xwl_pixmap->buffer);
free(xwl_pixmap);
return NULL;
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image);
glBindTexture(GL_TEXTURE_2D, 0);
pixmap = glamor_create_pixmap(screen, width, height, depth,
GLAMOR_CREATE_PIXMAP_NO_TEXTURE);
glamor_set_pixmap_texture(pixmap, texture);
glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
wl_buffer_add_listener(xwl_pixmap->buffer,
&xwl_eglstream_buffer_release_listener,
pixmap);
xwl_pixmap_set_private(pixmap, xwl_pixmap);
return pixmap;
}
static const dri3_screen_info_rec xwl_dri3_info = {
.version = 2,
.open = NULL,
.pixmap_from_fds = xwl_dri3_pixmap_from_fds,
.fds_from_pixmap = NULL,
.open_client = xwl_dri3_open_client,
.get_formats = xwl_glamor_get_formats,
.get_modifiers = xwl_glamor_get_modifiers,
.get_drawable_modifiers = glamor_get_drawable_modifiers,
};
static Bool
xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen)
{
@ -829,8 +991,10 @@ xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen)
#endif
eglBindAPI(EGL_OPENGL_API);
xwl_screen->egl_context = eglCreateContext(
xwl_screen->egl_display, config, EGL_NO_CONTEXT, attrib_list);
xwl_screen->egl_context = eglCreateContext(xwl_screen->egl_display,
EGL_NO_CONFIG_KHR,
EGL_NO_CONTEXT,
attrib_list);
if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
ErrorF("Failed to create main EGL context: 0x%x\n", eglGetError());
goto error;
@ -850,8 +1014,29 @@ xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen)
ErrorF("Driver lacks EGL_KHR_swap_buffers_with_damage, performance "
"will be affected\n");
#ifdef EGL_NV_stream_flush
xwl_eglstream->have_egl_stream_flush =
epoxy_has_egl_extension(xwl_screen->egl_display,
"EGL_NV_stream_flush");
#else
xwl_eglstream->have_egl_stream_flush = FALSE;
#endif /* EGL_NV_stream_flush */
if (!xwl_eglstream->have_egl_stream_flush)
ErrorF("EGL_NV_stream_flush not available, "
"this may cause visible corruption.\n");
xwl_eglstream_init_shaders(xwl_screen);
if (epoxy_has_gl_extension("GL_OES_EGL_image")) {
if (dri3_screen_init(xwl_screen->screen, &xwl_dri3_info))
xwl_screen->glvnd_vendor = "nvidia";
else
ErrorF("DRI3 initialization failed. Performance will be affected.\n");
} else {
ErrorF("Driver lacks GL_OES_EGL_image, performance will be affected.\n");
}
return TRUE;
error:
xwl_eglstream_cleanup(xwl_screen);
@ -861,20 +1046,11 @@ error:
static Bool
xwl_glamor_eglstream_init_screen(struct xwl_screen *xwl_screen)
{
struct xwl_eglstream_private *xwl_eglstream =
xwl_eglstream_get(xwl_screen);
ScreenPtr screen = xwl_screen->screen;
/* We can just let glamor handle CreatePixmap */
screen->DestroyPixmap = xwl_glamor_eglstream_destroy_pixmap;
xwl_eglstream->SetWindowPixmap = screen->SetWindowPixmap;
screen->SetWindowPixmap = xwl_eglstream_set_window_pixmap;
if (!dixRegisterPrivateKey(&xwl_eglstream_window_private_key,
PRIVATE_WINDOW, 0))
return FALSE;
return TRUE;
}
@ -905,7 +1081,7 @@ xwl_eglstream_get_device(struct xwl_screen *xwl_screen)
free(devices);
out:
if (!device)
ErrorF("glamor: No eglstream capable devices found\n");
LogMessageVerb(X_INFO, 3, "glamor: No eglstream capable devices found\n");
return device;
}
@ -933,7 +1109,6 @@ xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen)
&xwl_eglstream_private_key, xwl_eglstream);
xwl_eglstream->egl_device = egl_device;
xorg_list_init(&xwl_eglstream->pending_streams);
xwl_screen->eglstream_backend.init_egl = xwl_glamor_eglstream_init_egl;
xwl_screen->eglstream_backend.init_wl_registry = xwl_glamor_eglstream_init_wl_registry;
@ -942,6 +1117,7 @@ xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen)
xwl_screen->eglstream_backend.get_wl_buffer_for_pixmap = xwl_glamor_eglstream_get_wl_buffer_for_pixmap;
xwl_screen->eglstream_backend.post_damage = xwl_glamor_eglstream_post_damage;
xwl_screen->eglstream_backend.allow_commits = xwl_glamor_eglstream_allow_commits;
xwl_screen->eglstream_backend.check_flip = xwl_glamor_eglstream_check_flip;
xwl_screen->eglstream_backend.is_available = TRUE;
xwl_screen->eglstream_backend.backend_flags = XWL_EGL_BACKEND_NO_FLAG;
}

View File

@ -56,7 +56,6 @@ struct xwl_gbm_private {
char *device_name;
struct gbm_device *gbm;
struct wl_drm *drm;
struct zwp_linux_dmabuf_v1 *dmabuf;
int drm_fd;
int fd_render_node;
Bool drm_authenticated;
@ -98,25 +97,6 @@ gbm_format_for_depth(int depth)
}
}
static uint32_t
wl_drm_format_for_depth(int depth)
{
switch (depth) {
case 15:
return WL_DRM_FORMAT_XRGB1555;
case 16:
return WL_DRM_FORMAT_RGB565;
case 24:
return WL_DRM_FORMAT_XRGB8888;
case 30:
return WL_DRM_FORMAT_ARGB2101010;
default:
ErrorF("unexpected depth: %d\n", depth);
case 32:
return WL_DRM_FORMAT_ARGB8888;
}
}
static char
is_device_path_render_node (const char *device_path)
{
@ -140,6 +120,55 @@ xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo,
PixmapPtr pixmap;
struct xwl_pixmap *xwl_pixmap;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
#ifdef GBM_BO_FD_FOR_PLANE
struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
uint64_t modifier = gbm_bo_get_modifier(bo);
const int num_planes = gbm_bo_get_plane_count(bo);
int fds[GBM_MAX_PLANES];
int plane;
int attr_num = 0;
EGLint img_attrs[64] = {0};
enum PlaneAttrs {
PLANE_FD,
PLANE_OFFSET,
PLANE_PITCH,
PLANE_MODIFIER_LO,
PLANE_MODIFIER_HI,
NUM_PLANE_ATTRS
};
static const EGLint planeAttrs[][NUM_PLANE_ATTRS] = {
{
EGL_DMA_BUF_PLANE0_FD_EXT,
EGL_DMA_BUF_PLANE0_OFFSET_EXT,
EGL_DMA_BUF_PLANE0_PITCH_EXT,
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
},
{
EGL_DMA_BUF_PLANE1_FD_EXT,
EGL_DMA_BUF_PLANE1_OFFSET_EXT,
EGL_DMA_BUF_PLANE1_PITCH_EXT,
EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
},
{
EGL_DMA_BUF_PLANE2_FD_EXT,
EGL_DMA_BUF_PLANE2_OFFSET_EXT,
EGL_DMA_BUF_PLANE2_PITCH_EXT,
EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
},
{
EGL_DMA_BUF_PLANE3_FD_EXT,
EGL_DMA_BUF_PLANE3_OFFSET_EXT,
EGL_DMA_BUF_PLANE3_PITCH_EXT,
EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
},
};
for (plane = 0; plane < num_planes; plane++) fds[plane] = -1;
#endif
xwl_pixmap = calloc(1, sizeof(*xwl_pixmap));
if (xwl_pixmap == NULL)
@ -158,10 +187,57 @@ xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo,
xwl_glamor_egl_make_current(xwl_screen);
xwl_pixmap->bo = bo;
xwl_pixmap->buffer = NULL;
xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
xwl_screen->egl_context,
EGL_NATIVE_PIXMAP_KHR,
xwl_pixmap->bo, NULL);
#ifdef GBM_BO_FD_FOR_PLANE
if (xwl_gbm->dmabuf_capable) {
#define ADD_ATTR(attrs, num, attr) \
do { \
assert(((num) + 1) < (sizeof(attrs) / sizeof((attrs)[0]))); \
(attrs)[(num)++] = (attr); \
} while (0)
ADD_ATTR(img_attrs, attr_num, EGL_WIDTH);
ADD_ATTR(img_attrs, attr_num, gbm_bo_get_width(bo));
ADD_ATTR(img_attrs, attr_num, EGL_HEIGHT);
ADD_ATTR(img_attrs, attr_num, gbm_bo_get_height(bo));
ADD_ATTR(img_attrs, attr_num, EGL_LINUX_DRM_FOURCC_EXT);
ADD_ATTR(img_attrs, attr_num, gbm_bo_get_format(bo));
for (plane = 0; plane < num_planes; plane++) {
fds[plane] = gbm_bo_get_fd_for_plane(bo, plane);
ADD_ATTR(img_attrs, attr_num, planeAttrs[plane][PLANE_FD]);
ADD_ATTR(img_attrs, attr_num, fds[plane]);
ADD_ATTR(img_attrs, attr_num, planeAttrs[plane][PLANE_OFFSET]);
ADD_ATTR(img_attrs, attr_num, gbm_bo_get_offset(bo, plane));
ADD_ATTR(img_attrs, attr_num, planeAttrs[plane][PLANE_PITCH]);
ADD_ATTR(img_attrs, attr_num, gbm_bo_get_stride_for_plane(bo, plane));
ADD_ATTR(img_attrs, attr_num, planeAttrs[plane][PLANE_MODIFIER_LO]);
ADD_ATTR(img_attrs, attr_num, (uint32_t)(modifier & 0xFFFFFFFFULL));
ADD_ATTR(img_attrs, attr_num, planeAttrs[plane][PLANE_MODIFIER_HI]);
ADD_ATTR(img_attrs, attr_num, (uint32_t)(modifier >> 32ULL));
}
ADD_ATTR(img_attrs, attr_num, EGL_NONE);
#undef ADD_ATTR
xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT,
NULL,
img_attrs);
for (plane = 0; plane < num_planes; plane++) {
close(fds[plane]);
fds[plane] = -1;
}
}
else
#endif
{
xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
xwl_screen->egl_context,
EGL_NATIVE_PIXMAP_KHR,
xwl_pixmap->bo, NULL);
}
if (xwl_pixmap->image == EGL_NO_IMAGE_KHR)
goto error;
@ -215,7 +291,7 @@ xwl_glamor_gbm_create_pixmap(ScreenPtr screen,
uint32_t num_modifiers;
uint64_t *modifiers = NULL;
glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
xwl_glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
bo = gbm_bo_create_with_modifiers(xwl_gbm->gbm, width, height,
format, modifiers, num_modifiers);
free(modifiers);
@ -278,8 +354,6 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap)
unsigned short width = pixmap->drawable.width;
unsigned short height = pixmap->drawable.height;
uint32_t format;
struct xwl_format *xwl_format = NULL;
Bool modifier_supported = FALSE;
int prime_fd;
int num_planes;
uint32_t strides[4];
@ -318,26 +392,11 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap)
offsets[0] = 0;
#endif
for (i = 0; i < xwl_screen->num_formats; i++) {
if (xwl_screen->formats[i].format == format) {
xwl_format = &xwl_screen->formats[i];
break;
}
}
if (xwl_format) {
for (i = 0; i < xwl_format->num_modifiers; i++) {
if (xwl_format->modifiers[i] == modifier) {
modifier_supported = TRUE;
break;
}
}
}
if (xwl_gbm->dmabuf && modifier_supported) {
if (xwl_screen->dmabuf &&
xwl_glamor_is_modifier_supported(xwl_screen, format, modifier)) {
struct zwp_linux_buffer_params_v1 *params;
params = zwp_linux_dmabuf_v1_create_params(xwl_gbm->dmabuf);
params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf);
for (i = 0; i < num_planes; i++) {
zwp_linux_buffer_params_v1_add(params, prime_fd, i,
offsets[i], strides[i],
@ -593,83 +652,14 @@ glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
return -1;
}
_X_EXPORT Bool
glamor_get_formats(ScreenPtr screen,
CARD32 *num_formats, CARD32 **formats)
{
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
int i;
/* Explicitly zero the count as the caller may ignore the return value */
*num_formats = 0;
if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf)
return FALSE;
if (xwl_screen->num_formats == 0)
return TRUE;
*formats = calloc(xwl_screen->num_formats, sizeof(CARD32));
if (*formats == NULL)
return FALSE;
for (i = 0; i < xwl_screen->num_formats; i++)
(*formats)[i] = xwl_screen->formats[i].format;
*num_formats = xwl_screen->num_formats;
return TRUE;
}
_X_EXPORT Bool
glamor_get_modifiers(ScreenPtr screen, uint32_t format,
uint32_t *num_modifiers, uint64_t **modifiers)
{
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
struct xwl_format *xwl_format = NULL;
int i;
/* Explicitly zero the count as the caller may ignore the return value */
*num_modifiers = 0;
if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf)
return FALSE;
if (xwl_screen->num_formats == 0)
return TRUE;
for (i = 0; i < xwl_screen->num_formats; i++) {
if (xwl_screen->formats[i].format == format) {
xwl_format = &xwl_screen->formats[i];
break;
}
}
if (!xwl_format ||
(xwl_format->num_modifiers == 1 &&
xwl_format->modifiers[0] == DRM_FORMAT_MOD_INVALID))
return FALSE;
*modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t));
if (*modifiers == NULL)
return FALSE;
for (i = 0; i < xwl_format->num_modifiers; i++)
(*modifiers)[i] = xwl_format->modifiers[i];
*num_modifiers = xwl_format->num_modifiers;
return TRUE;
}
static const dri3_screen_info_rec xwl_dri3_info = {
.version = 2,
.open = NULL,
.pixmap_from_fds = glamor_pixmap_from_fds,
.fds_from_pixmap = glamor_fds_from_pixmap,
.open_client = xwl_dri3_open_client,
.get_formats = glamor_get_formats,
.get_modifiers = glamor_get_modifiers,
.get_formats = xwl_glamor_get_formats,
.get_modifiers = xwl_glamor_get_modifiers,
.get_drawable_modifiers = glamor_get_drawable_modifiers,
};
@ -797,54 +787,6 @@ static const struct wl_drm_listener xwl_drm_listener = {
xwl_drm_handle_capabilities
};
static void
xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
uint32_t format)
{
}
static void
xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
uint32_t format, uint32_t modifier_hi,
uint32_t modifier_lo)
{
struct xwl_screen *xwl_screen = data;
struct xwl_format *xwl_format = NULL;
int i;
for (i = 0; i < xwl_screen->num_formats; i++) {
if (xwl_screen->formats[i].format == format) {
xwl_format = &xwl_screen->formats[i];
break;
}
}
if (xwl_format == NULL) {
xwl_screen->num_formats++;
xwl_screen->formats = realloc(xwl_screen->formats,
xwl_screen->num_formats * sizeof(*xwl_format));
if (!xwl_screen->formats)
return;
xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1];
xwl_format->format = format;
xwl_format->num_modifiers = 0;
xwl_format->modifiers = NULL;
}
xwl_format->num_modifiers++;
xwl_format->modifiers = realloc(xwl_format->modifiers,
xwl_format->num_modifiers * sizeof(uint64_t));
if (!xwl_format->modifiers)
return;
xwl_format->modifiers[xwl_format->num_modifiers - 1] = (uint64_t) modifier_lo;
xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32;
}
static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = {
.format = xwl_dmabuf_handle_format,
.modifier = xwl_dmabuf_handle_modifier
};
Bool
xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
uint32_t id, uint32_t version)
@ -862,22 +804,6 @@ xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
return TRUE;
}
Bool
xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
uint32_t id, uint32_t version)
{
struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
if (version < 3)
return FALSE;
xwl_gbm->dmabuf =
wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
zwp_linux_dmabuf_v1_add_listener(xwl_gbm->dmabuf, &xwl_dmabuf_listener, xwl_screen);
return TRUE;
}
static Bool
xwl_glamor_gbm_init_wl_registry(struct xwl_screen *xwl_screen,
struct wl_registry *wl_registry,
@ -909,7 +835,7 @@ xwl_glamor_gbm_has_wl_interfaces(struct xwl_screen *xwl_screen)
struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
if (xwl_gbm->drm == NULL) {
ErrorF("glamor: 'wl_drm' not supported\n");
LogMessageVerb(X_INFO, 3, "glamor: 'wl_drm' not supported\n");
return FALSE;
}
@ -955,12 +881,12 @@ xwl_glamor_try_big_gl_api(struct xwl_screen *xwl_screen)
eglBindAPI(EGL_OPENGL_API);
xwl_screen->egl_context =
eglCreateContext(xwl_screen->egl_display, NULL,
eglCreateContext(xwl_screen->egl_display, EGL_NO_CONFIG_KHR,
EGL_NO_CONTEXT, config_attribs_core);
if (xwl_screen->egl_context == EGL_NO_CONTEXT)
xwl_screen->egl_context =
eglCreateContext(xwl_screen->egl_display, NULL,
eglCreateContext(xwl_screen->egl_display, EGL_NO_CONFIG_KHR,
EGL_NO_CONTEXT, NULL);
if (!xwl_glamor_try_to_make_context_current(xwl_screen)) {
@ -994,7 +920,8 @@ xwl_glamor_try_gles_api(struct xwl_screen *xwl_screen)
eglBindAPI(EGL_OPENGL_ES_API);
xwl_screen->egl_context = eglCreateContext(xwl_screen->egl_display, NULL,
xwl_screen->egl_context = eglCreateContext(xwl_screen->egl_display,
EGL_NO_CONFIG_KHR,
EGL_NO_CONTEXT, gles_attribs);
if (!xwl_glamor_try_to_make_context_current(xwl_screen)) {
@ -1012,6 +939,7 @@ xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen)
struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
EGLint major, minor;
const GLubyte *renderer;
const char *gbm_backend_name;
if (!xwl_gbm->fd_render_node && !xwl_gbm->drm_authenticated) {
ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n");
@ -1063,6 +991,11 @@ xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen)
"EXT_image_dma_buf_import_modifiers"))
xwl_gbm->dmabuf_capable = TRUE;
gbm_backend_name = gbm_device_get_backend_name(xwl_gbm->gbm);
/* Mesa uses "drm" as backend name, in that case, just do nothing */
if (gbm_backend_name && strcmp(gbm_backend_name, "drm") != 0)
xwl_screen->glvnd_vendor = gbm_backend_name;
return TRUE;
error:
if (xwl_screen->egl_display != EGL_NO_DISPLAY) {
@ -1137,8 +1070,8 @@ xwl_glamor_init_gbm(struct xwl_screen *xwl_screen)
xwl_screen->gbm_backend.init_egl = xwl_glamor_gbm_init_egl;
xwl_screen->gbm_backend.init_screen = xwl_glamor_gbm_init_screen;
xwl_screen->gbm_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap;
xwl_screen->gbm_backend.check_flip = NULL;
xwl_screen->gbm_backend.is_available = TRUE;
xwl_screen->gbm_backend.backend_flags = XWL_EGL_BACKEND_HAS_PRESENT_FLIP |
XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH |
xwl_screen->gbm_backend.backend_flags = XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH |
XWL_EGL_BACKEND_NEEDS_N_BUFFERING;
}

View File

@ -35,6 +35,10 @@
#include "glx_extinit.h"
#endif
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "drm-client-protocol.h"
#include <drm_fourcc.h>
#include "xwayland-glamor.h"
#include "xwayland-glx.h"
#include "xwayland-screen.h"
@ -54,10 +58,12 @@ glamor_egl_make_current(struct glamor_context *glamor_ctx)
void
xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen)
{
if (lastGLContext == xwl_screen->glamor_ctx)
EGLContext ctx = xwl_screen->glamor_ctx->ctx;
if (lastGLContext == ctx)
return;
lastGLContext = xwl_screen->glamor_ctx;
lastGLContext = ctx;
xwl_screen->glamor_ctx->make_current(xwl_screen->glamor_ctx);
}
@ -75,6 +81,193 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
xwl_screen->glamor_ctx = glamor_ctx;
}
Bool
xwl_glamor_check_flip(PixmapPtr pixmap)
{
struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
if (!xwl_glamor_pixmap_get_wl_buffer(pixmap))
return FALSE;
if (xwl_screen->egl_backend->check_flip)
return xwl_screen->egl_backend->check_flip(pixmap);
return TRUE;
}
Bool
xwl_glamor_is_modifier_supported(struct xwl_screen *xwl_screen,
uint32_t format, uint64_t modifier)
{
struct xwl_format *xwl_format = NULL;
int i;
for (i = 0; i < xwl_screen->num_formats; i++) {
if (xwl_screen->formats[i].format == format) {
xwl_format = &xwl_screen->formats[i];
break;
}
}
if (xwl_format) {
for (i = 0; i < xwl_format->num_modifiers; i++) {
if (xwl_format->modifiers[i] == modifier) {
return TRUE;
}
}
}
return FALSE;
}
uint32_t
wl_drm_format_for_depth(int depth)
{
switch (depth) {
case 15:
return WL_DRM_FORMAT_XRGB1555;
case 16:
return WL_DRM_FORMAT_RGB565;
case 24:
return WL_DRM_FORMAT_XRGB8888;
case 30:
return WL_DRM_FORMAT_ARGB2101010;
default:
ErrorF("unexpected depth: %d\n", depth);
case 32:
return WL_DRM_FORMAT_ARGB8888;
}
}
Bool
xwl_glamor_get_formats(ScreenPtr screen,
CARD32 *num_formats, CARD32 **formats)
{
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
int i;
/* Explicitly zero the count as the caller may ignore the return value */
*num_formats = 0;
if (!xwl_screen->dmabuf)
return FALSE;
if (xwl_screen->num_formats == 0)
return TRUE;
*formats = calloc(xwl_screen->num_formats, sizeof(CARD32));
if (*formats == NULL)
return FALSE;
for (i = 0; i < xwl_screen->num_formats; i++)
(*formats)[i] = xwl_screen->formats[i].format;
*num_formats = xwl_screen->num_formats;
return TRUE;
}
Bool
xwl_glamor_get_modifiers(ScreenPtr screen, uint32_t format,
uint32_t *num_modifiers, uint64_t **modifiers)
{
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
struct xwl_format *xwl_format = NULL;
int i;
/* Explicitly zero the count as the caller may ignore the return value */
*num_modifiers = 0;
if (!xwl_screen->dmabuf)
return FALSE;
if (xwl_screen->num_formats == 0)
return TRUE;
for (i = 0; i < xwl_screen->num_formats; i++) {
if (xwl_screen->formats[i].format == format) {
xwl_format = &xwl_screen->formats[i];
break;
}
}
if (!xwl_format ||
(xwl_format->num_modifiers == 1 &&
xwl_format->modifiers[0] == DRM_FORMAT_MOD_INVALID))
return FALSE;
*modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t));
if (*modifiers == NULL)
return FALSE;
for (i = 0; i < xwl_format->num_modifiers; i++)
(*modifiers)[i] = xwl_format->modifiers[i];
*num_modifiers = xwl_format->num_modifiers;
return TRUE;
}
static void
xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
uint32_t format)
{
}
static void
xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
uint32_t format, uint32_t modifier_hi,
uint32_t modifier_lo)
{
struct xwl_screen *xwl_screen = data;
struct xwl_format *xwl_format = NULL;
int i;
for (i = 0; i < xwl_screen->num_formats; i++) {
if (xwl_screen->formats[i].format == format) {
xwl_format = &xwl_screen->formats[i];
break;
}
}
if (xwl_format == NULL) {
xwl_screen->num_formats++;
xwl_screen->formats = realloc(xwl_screen->formats,
xwl_screen->num_formats * sizeof(*xwl_format));
if (!xwl_screen->formats)
return;
xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1];
xwl_format->format = format;
xwl_format->num_modifiers = 0;
xwl_format->modifiers = NULL;
}
xwl_format->num_modifiers++;
xwl_format->modifiers = realloc(xwl_format->modifiers,
xwl_format->num_modifiers * sizeof(uint64_t));
if (!xwl_format->modifiers)
return;
xwl_format->modifiers[xwl_format->num_modifiers - 1] = (uint64_t) modifier_lo;
xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32;
}
static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = {
.format = xwl_dmabuf_handle_format,
.modifier = xwl_dmabuf_handle_modifier
};
Bool
xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
uint32_t id, uint32_t version)
{
if (version < 3)
return FALSE;
xwl_screen->dmabuf =
wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
zwp_linux_dmabuf_v1_add_listener(xwl_screen->dmabuf, &xwl_dmabuf_listener, xwl_screen);
return TRUE;
}
void
xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen,
struct wl_registry *registry,
@ -89,11 +282,11 @@ xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen,
version)) {
/* no-op */
} else if (xwl_screen->eglstream_backend.is_available &&
xwl_screen->eglstream_backend.init_wl_registry(xwl_screen,
registry,
id,
interface,
version)) {
xwl_screen->eglstream_backend.init_wl_registry(xwl_screen,
registry,
id,
interface,
version)) {
/* no-op */
}
}
@ -116,14 +309,16 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
return NULL;
}
void
Bool
xwl_glamor_post_damage(struct xwl_window *xwl_window,
PixmapPtr pixmap, RegionPtr region)
{
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
if (xwl_screen->egl_backend->post_damage)
xwl_screen->egl_backend->post_damage(xwl_window, pixmap, region);
return xwl_screen->egl_backend->post_damage(xwl_window, pixmap, region);
return TRUE;
}
Bool
@ -174,16 +369,6 @@ glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
return 0;
}
Bool
xwl_glamor_has_present_flip(struct xwl_screen *xwl_screen)
{
if (!xwl_screen->glamor || !xwl_screen->egl_backend)
return FALSE;
return (xwl_screen->egl_backend->backend_flags &
XWL_EGL_BACKEND_HAS_PRESENT_FLIP);
}
Bool
xwl_glamor_needs_buffer_flush(struct xwl_screen *xwl_screen)
{
@ -227,10 +412,12 @@ xwl_glamor_select_gbm_backend(struct xwl_screen *xwl_screen)
if (xwl_screen->gbm_backend.is_available &&
xwl_glamor_has_wl_interfaces(xwl_screen, &xwl_screen->gbm_backend)) {
xwl_screen->egl_backend = &xwl_screen->gbm_backend;
LogMessageVerb(X_INFO, 3, "glamor: Using GBM backend\n");
return TRUE;
}
else
ErrorF("Missing Wayland requirements for glamor GBM backend\n");
LogMessageVerb(X_INFO, 3,
"Missing Wayland requirements for glamor GBM backend\n");
#endif
return FALSE;
@ -242,13 +429,13 @@ xwl_glamor_select_eglstream_backend(struct xwl_screen *xwl_screen)
#ifdef XWL_HAS_EGLSTREAM
if (xwl_screen->eglstream_backend.is_available &&
xwl_glamor_has_wl_interfaces(xwl_screen, &xwl_screen->eglstream_backend)) {
ErrorF("glamor: Using nvidia's EGLStream interface, direct rendering impossible.\n");
ErrorF("glamor: Performance may be affected. Ask your vendor to support GBM!\n");
xwl_screen->egl_backend = &xwl_screen->eglstream_backend;
LogMessageVerb(X_INFO, 3, "glamor: Using EGLStream backend\n");
return TRUE;
}
else
ErrorF("Missing Wayland requirements for glamor EGLStream backend\n");
LogMessageVerb(X_INFO, 3,
"Missing Wayland requirements for glamor EGLStream backend\n");
#endif
return FALSE;
@ -257,14 +444,10 @@ xwl_glamor_select_eglstream_backend(struct xwl_screen *xwl_screen)
void
xwl_glamor_select_backend(struct xwl_screen *xwl_screen, Bool use_eglstream)
{
if (use_eglstream) {
if (!xwl_glamor_select_eglstream_backend(xwl_screen))
if (!xwl_glamor_select_eglstream_backend(xwl_screen)) {
if (!use_eglstream)
xwl_glamor_select_gbm_backend(xwl_screen);
}
else {
if (!xwl_glamor_select_gbm_backend(xwl_screen))
xwl_glamor_select_eglstream_backend(xwl_screen);
}
}
Bool

View File

@ -34,9 +34,8 @@
typedef enum _xwl_egl_backend_flags {
XWL_EGL_BACKEND_NO_FLAG = 0,
XWL_EGL_BACKEND_HAS_PRESENT_FLIP = (1 << 0),
XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH = (1 << 1),
XWL_EGL_BACKEND_NEEDS_N_BUFFERING = (1 << 2),
XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH = (1 << 0),
XWL_EGL_BACKEND_NEEDS_N_BUFFERING = (1 << 1),
} xwl_egl_backend_flags;
struct xwl_egl_backend {
@ -84,7 +83,7 @@ struct xwl_egl_backend {
* you should implement blitting from the glamor pixmap to the wayland
* pixmap here. Otherwise, this callback is optional.
*/
void (*post_damage)(struct xwl_window *xwl_window,
Bool (*post_damage)(struct xwl_window *xwl_window,
PixmapPtr pixmap, RegionPtr region);
/* Called by Xwayland to confirm with the egl backend that the given
@ -92,6 +91,11 @@ struct xwl_egl_backend {
* callback is optional.
*/
Bool (*allow_commits)(struct xwl_window *xwl_window);
/* Called by Xwayland to check whether the given pixmap can be
* presented by xwl_present_flip. If not implemented, assumed TRUE.
*/
Bool (*check_flip)(PixmapPtr pixmap);
};
#ifdef XWL_HAS_GLAMOR
@ -113,14 +117,20 @@ void xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen,
uint32_t version);
Bool xwl_glamor_has_wl_interfaces(struct xwl_screen *xwl_screen,
struct xwl_egl_backend *xwl_egl_backend);
void xwl_glamor_post_damage(struct xwl_window *xwl_window,
Bool xwl_glamor_post_damage(struct xwl_window *xwl_window,
PixmapPtr pixmap, RegionPtr region);
Bool xwl_glamor_allow_commits(struct xwl_window *xwl_window);
void xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen);
Bool xwl_glamor_has_present_flip(struct xwl_screen *xwl_screen);
Bool xwl_glamor_needs_buffer_flush(struct xwl_screen *xwl_screen);
Bool xwl_glamor_needs_n_buffering(struct xwl_screen *xwl_screen);
Bool xwl_glamor_is_modifier_supported(struct xwl_screen *xwl_screen,
uint32_t format, uint64_t modifier);
uint32_t wl_drm_format_for_depth(int depth);
Bool xwl_glamor_get_formats(ScreenPtr screen,
CARD32 *num_formats, CARD32 **formats);
Bool xwl_glamor_get_modifiers(ScreenPtr screen, uint32_t format,
uint32_t *num_modifiers, uint64_t **modifiers);
Bool xwl_glamor_check_flip(PixmapPtr pixmap);
#ifdef XV
/* glamor Xv Adaptor */

View File

@ -138,7 +138,6 @@ egl_create_glx_drawable(ClientPtr client, __GLXscreen *screen,
/*
* TODO:
*
* - figure out sRGB
* - bindToTextureTargets is suspicious
* - better channel mask setup
* - drawable type masks is suspicious
@ -146,7 +145,8 @@ egl_create_glx_drawable(ClientPtr client, __GLXscreen *screen,
static struct egl_config *
translate_eglconfig(struct egl_screen *screen, EGLConfig hc,
struct egl_config *chain, Bool direct_color,
Bool double_buffer, Bool duplicate_for_composite)
Bool double_buffer, Bool duplicate_for_composite,
Bool srgb_only)
{
EGLint value;
struct egl_config *c = calloc(1, sizeof *c);
@ -167,7 +167,6 @@ translate_eglconfig(struct egl_screen *screen, EGLConfig hc,
c->base.optimalPbufferHeight = 0;
c->base.bindToMipmapTexture = 0;
c->base.bindToTextureTargets = GLX_DONT_CARE;
c->base.sRGBCapable = 0;
c->base.swapMethod = GLX_SWAP_UNDEFINED_OML;
/* this is... suspect */
@ -242,6 +241,19 @@ translate_eglconfig(struct egl_screen *screen, EGLConfig hc,
/* else panic */
}
/* derived state: sRGB. EGL doesn't put this in the fbconfig at all,
* it's a property of the surface specified at creation time, so we have
* to infer it from the GL's extensions. only makes sense at 8bpc though.
*/
if (srgb_only) {
if (c->base.redBits == 8) {
c->base.sRGBCapable = GL_TRUE;
} else {
free(c);
return chain;
}
}
/* map to the backend's config */
c->config = hc;
@ -314,6 +326,9 @@ egl_mirror_configs(ScreenPtr pScreen, struct egl_screen *screen)
int i, j, k, nconfigs;
struct egl_config *c = NULL;
EGLConfig *host_configs = NULL;
bool can_srgb = epoxy_has_gl_extension("GL_ARB_framebuffer_sRGB") ||
epoxy_has_gl_extension("GL_EXT_framebuffer_sRGB") ||
epoxy_has_gl_extension("GL_EXT_sRGB_write_control");
eglGetConfigs(screen->display, NULL, 0, &nconfigs);
if (!(host_configs = calloc(nconfigs, sizeof *host_configs)))
@ -326,11 +341,20 @@ egl_mirror_configs(ScreenPtr pScreen, struct egl_screen *screen)
*/
for (i = nconfigs - 1; i > 0; i--)
for (j = 0; j < 3; j++) /* direct_color */
for (k = 0; k < 2; k++) /* double_buffer */
for (k = 0; k < 2; k++) /* double_buffer */ {
if (can_srgb)
c = translate_eglconfig(screen, host_configs[i], c,
/* direct_color */ j == 1,
/* double_buffer */ k > 0,
/* duplicate_for_composite */ j == 0,
/* srgb_only */ true);
c = translate_eglconfig(screen, host_configs[i], c,
/* direct_color */ j == 1,
/* double_buffer */ k > 0,
/* duplicate_for_composite */ j == 0);
/* duplicate_for_composite */ j == 0,
/* srgb_only */ false);
}
screen->configs = host_configs;
return c ? &c->base : NULL;
@ -378,6 +402,9 @@ egl_screen_probe(ScreenPtr pScreen)
return NULL;
}
if (!screen->base.glvnd && xwl_screen->glvnd_vendor)
screen->base.glvnd = strdup(xwl_screen->glvnd_vendor);
if (!screen->base.glvnd)
screen->base.glvnd = strdup("mesa");

View File

@ -47,6 +47,7 @@
#include "pointer-constraints-unstable-v1-client-protocol.h"
#include "relative-pointer-unstable-v1-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#include "pointer-gestures-unstable-v1-client-protocol.h"
#include "xwayland-keyboard-grab-unstable-v1-client-protocol.h"
struct axis_discrete_pending {
@ -242,6 +243,51 @@ xwl_pointer_proc_relative(DeviceIntPtr device, int what)
#undef NAXES
}
static int
xwl_pointer_proc_pointer_gestures(DeviceIntPtr device, int what)
{
#define NTOUCHPOINTS 20
#define NAXES 2
Atom axes_labels[NAXES] = { 0 };
switch (what) {
case DEVICE_INIT:
device->public.on = FALSE;
/* We need to setup a pointer device so that the device is attached to
master pointer device.
*/
axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
if (!InitValuatorClassDeviceStruct(device, NAXES, axes_labels,
GetMotionHistorySize(), Relative))
return BadValue;
InitValuatorAxisStruct(device, 0, axes_labels[0],
NO_AXIS_LIMITS, NO_AXIS_LIMITS, 0, 0, 0, Relative);
InitValuatorAxisStruct(device, 1, axes_labels[1],
NO_AXIS_LIMITS, NO_AXIS_LIMITS, 0, 0, 0, Relative);
InitGestureClassDeviceStruct(device, NTOUCHPOINTS);
return Success;
case DEVICE_ON:
device->public.on = TRUE;
return Success;
case DEVICE_OFF:
case DEVICE_CLOSE:
device->public.on = FALSE;
return Success;
}
return BadMatch;
#undef NTOUCHPOINTS
#undef NAXES
}
static void
xwl_keyboard_control(DeviceIntPtr device, KeybdCtrl *ctrl)
{
@ -427,6 +473,9 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
if (surface == NULL)
return;
if (!is_surface_from_xwl_window(surface))
return;
xwl_seat->xwl_screen->serial = serial;
xwl_seat->pointer_enter_serial = serial;
@ -463,11 +512,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
* of our surfaces might not have been shown. In that case we'll
* have a cursor surface frame callback pending which we need to
* clear so that we can continue submitting new cursor frames. */
if (xwl_seat->cursor.frame_cb) {
wl_callback_destroy(xwl_seat->cursor.frame_cb);
xwl_seat->cursor.frame_cb = NULL;
if (xwl_cursor_clear_frame_cb(&xwl_seat->cursor))
xwl_seat_set_cursor(xwl_seat);
}
if (xwl_seat->pointer_warp_emulator) {
xwl_pointer_warp_emulator_maybe_lock(xwl_seat->pointer_warp_emulator,
@ -758,6 +804,138 @@ static const struct zwp_relative_pointer_v1_listener relative_pointer_listener =
relative_pointer_handle_relative_motion,
};
static void
pointer_gesture_swipe_handle_begin(void *data,
struct zwp_pointer_gesture_swipe_v1 *swipe,
uint32_t serial,
uint32_t time,
struct wl_surface *surface,
uint32_t fingers)
{
struct xwl_seat *xwl_seat = data;
if (surface != NULL && !is_surface_from_xwl_window(surface))
return;
xwl_seat->pointer_gesture_swipe_fingers = fingers;
QueueGestureSwipeEvents(xwl_seat->pointer_gestures,
XI_GestureSwipeBegin, fingers, 0, 0.0, 0.0, 0.0, 0.0);
}
static void
pointer_gesture_swipe_handle_update(void *data,
struct zwp_pointer_gesture_swipe_v1 *swipe,
uint32_t time,
wl_fixed_t dxf,
wl_fixed_t dyf)
{
struct xwl_seat *xwl_seat = data;
double dx = wl_fixed_to_double(dxf);
double dy = wl_fixed_to_double(dyf);
QueueGestureSwipeEvents(xwl_seat->pointer_gestures,
XI_GestureSwipeUpdate,
xwl_seat->pointer_gesture_swipe_fingers,
0,
dx, dy,
dx, dy);
}
static void
pointer_gesture_swipe_handle_end(void *data,
struct zwp_pointer_gesture_swipe_v1 *swipe,
uint32_t serial,
uint32_t time,
int32_t cancelled)
{
struct xwl_seat *xwl_seat = data;
uint32_t flags = 0;
if (cancelled)
flags |= XIGestureSwipeEventCancelled;
QueueGestureSwipeEvents(xwl_seat->pointer_gestures,
XI_GestureSwipeEnd,
xwl_seat->pointer_gesture_swipe_fingers,
flags, 0.0, 0.0, 0.0, 0.0);
}
static const struct zwp_pointer_gesture_swipe_v1_listener pointer_gesture_swipe_listener = {
pointer_gesture_swipe_handle_begin,
pointer_gesture_swipe_handle_update,
pointer_gesture_swipe_handle_end
};
static void
pointer_gesture_pinch_handle_begin(void *data,
struct zwp_pointer_gesture_pinch_v1 *pinch,
uint32_t serial,
uint32_t time,
struct wl_surface *surface,
uint32_t fingers)
{
struct xwl_seat *xwl_seat = data;
if (surface != NULL && !is_surface_from_xwl_window(surface))
return;
xwl_seat->pointer_gesture_pinch_fingers = fingers;
xwl_seat->pointer_gesture_pinch_last_scale = 1.0;
QueueGesturePinchEvents(xwl_seat->pointer_gestures,
XI_GesturePinchBegin, fingers, 0, 0.0, 0.0, 0.0, 0.0,
1.0, 0.0);
}
static void
pointer_gesture_pinch_handle_update(void *data,
struct zwp_pointer_gesture_pinch_v1 *pinch,
uint32_t time,
wl_fixed_t dxf,
wl_fixed_t dyf,
wl_fixed_t scalef,
wl_fixed_t rotation)
{
struct xwl_seat *xwl_seat = data;
double dx = wl_fixed_to_double(dxf);
double dy = wl_fixed_to_double(dyf);
double scale = wl_fixed_to_double(scalef);
xwl_seat->pointer_gesture_pinch_last_scale = scale;
QueueGesturePinchEvents(xwl_seat->pointer_gestures,
XI_GesturePinchUpdate,
xwl_seat->pointer_gesture_pinch_fingers,
0,
dx, dy,
dx, dy,
scale, wl_fixed_to_double(rotation));
}
static void
pointer_gesture_pinch_handle_end(void *data,
struct zwp_pointer_gesture_pinch_v1 *pinch,
uint32_t serial,
uint32_t time,
int32_t cancelled)
{
struct xwl_seat *xwl_seat = data;
uint32_t flags = 0;
if (cancelled)
flags |= XIGesturePinchEventCancelled;
QueueGesturePinchEvents(xwl_seat->pointer_gestures,
XI_GesturePinchEnd,
xwl_seat->pointer_gesture_pinch_fingers,
flags, 0.0, 0.0, 0.0, 0.0,
xwl_seat->pointer_gesture_pinch_last_scale, 0.0);
}
static const struct zwp_pointer_gesture_pinch_v1_listener pointer_gesture_pinch_listener = {
pointer_gesture_pinch_handle_begin,
pointer_gesture_pinch_handle_update,
pointer_gesture_pinch_handle_end
};
static void
keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial,
uint32_t time, uint32_t key, uint32_t state)
@ -834,6 +1012,9 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
struct xwl_seat *xwl_seat = data;
uint32_t *k;
if (surface != NULL && !is_surface_from_xwl_window(surface))
return;
xwl_seat->xwl_screen->serial = serial;
xwl_seat->keyboard_focus = surface;
@ -1049,6 +1230,9 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
if (surface == NULL)
return;
if (!is_surface_from_xwl_window(surface))
return;
xwl_touch = calloc(1, sizeof *xwl_touch);
if (xwl_touch == NULL) {
ErrorF("%s: ENOMEM\n", __func__);
@ -1300,6 +1484,18 @@ release_pointer(struct xwl_seat *xwl_seat)
static void
init_relative_pointer(struct xwl_seat *xwl_seat)
{
if (xwl_seat->relative_pointer == NULL) {
xwl_seat->relative_pointer =
add_device(xwl_seat, "xwayland-relative-pointer",
xwl_pointer_proc_relative);
ActivateDevice(xwl_seat->relative_pointer, TRUE);
}
enable_device(xwl_seat, xwl_seat->relative_pointer);
}
static void
init_relative_pointer_listener(struct xwl_seat *xwl_seat)
{
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager =
xwl_seat->xwl_screen->relative_pointer_manager;
@ -1312,14 +1508,6 @@ init_relative_pointer(struct xwl_seat *xwl_seat)
&relative_pointer_listener,
xwl_seat);
}
if (xwl_seat->relative_pointer == NULL) {
xwl_seat->relative_pointer =
add_device(xwl_seat, "xwayland-relative-pointer",
xwl_pointer_proc_relative);
ActivateDevice(xwl_seat->relative_pointer, TRUE);
}
enable_device(xwl_seat, xwl_seat->relative_pointer);
}
static void
@ -1334,6 +1522,64 @@ release_relative_pointer(struct xwl_seat *xwl_seat)
disable_device(xwl_seat->relative_pointer);
}
static void
init_pointer_gestures_device(struct xwl_seat *xwl_seat)
{
if (xwl_seat->pointer_gestures == NULL) {
xwl_seat->pointer_gestures =
add_device(xwl_seat, "xwayland-pointer-gestures",
xwl_pointer_proc_pointer_gestures);
ActivateDevice(xwl_seat->pointer_gestures, TRUE);
}
enable_device(xwl_seat, xwl_seat->pointer_gestures);
}
static void
init_pointer_gestures_listener(struct xwl_seat *xwl_seat)
{
struct zwp_pointer_gestures_v1 *pointer_gestures =
xwl_seat->xwl_screen->pointer_gestures;
if (pointer_gestures && !xwl_seat->wp_pointer_gesture_swipe) {
xwl_seat->wp_pointer_gesture_swipe =
zwp_pointer_gestures_v1_get_swipe_gesture(pointer_gestures,
xwl_seat->wl_pointer);
zwp_pointer_gesture_swipe_v1_set_user_data(xwl_seat->wp_pointer_gesture_swipe,
xwl_seat);
zwp_pointer_gesture_swipe_v1_add_listener(xwl_seat->wp_pointer_gesture_swipe,
&pointer_gesture_swipe_listener,
xwl_seat);
}
if (pointer_gestures && !xwl_seat->wp_pointer_gesture_pinch) {
xwl_seat->wp_pointer_gesture_pinch =
zwp_pointer_gestures_v1_get_pinch_gesture(pointer_gestures,
xwl_seat->wl_pointer);
zwp_pointer_gesture_pinch_v1_set_user_data(xwl_seat->wp_pointer_gesture_pinch,
xwl_seat);
zwp_pointer_gesture_pinch_v1_add_listener(xwl_seat->wp_pointer_gesture_pinch,
&pointer_gesture_pinch_listener,
xwl_seat);
}
}
static void
release_pointer_gestures_device(struct xwl_seat *xwl_seat)
{
if (xwl_seat->wp_pointer_gesture_swipe) {
zwp_pointer_gesture_swipe_v1_destroy(xwl_seat->wp_pointer_gesture_swipe);
xwl_seat->wp_pointer_gesture_swipe = NULL;
}
if (xwl_seat->wp_pointer_gesture_pinch) {
zwp_pointer_gesture_pinch_v1_destroy(xwl_seat->wp_pointer_gesture_pinch);
xwl_seat->wp_pointer_gesture_pinch = NULL;
}
if (xwl_seat->pointer_gestures)
disable_device(xwl_seat->pointer_gestures);
}
static void
init_keyboard(struct xwl_seat *xwl_seat)
{
@ -1406,9 +1652,13 @@ seat_handle_capabilities(void *data, struct wl_seat *seat,
if (caps & WL_SEAT_CAPABILITY_POINTER && xwl_seat->wl_pointer == NULL) {
init_pointer(xwl_seat);
init_relative_pointer(xwl_seat);
init_relative_pointer_listener(xwl_seat);
init_pointer_gestures_device(xwl_seat);
init_pointer_gestures_listener(xwl_seat);
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && xwl_seat->wl_pointer) {
release_pointer(xwl_seat);
release_relative_pointer(xwl_seat);
release_pointer_gestures_device(xwl_seat);
}
if (caps & WL_SEAT_CAPABILITY_KEYBOARD && xwl_seat->wl_keyboard == NULL) {
@ -1448,14 +1698,6 @@ xwl_cursor_init(struct xwl_cursor *xwl_cursor, struct xwl_screen *xwl_screen,
xwl_cursor->needs_update = FALSE;
}
static void
xwl_cursor_release(struct xwl_cursor *xwl_cursor)
{
wl_surface_destroy(xwl_cursor->surface);
if (xwl_cursor->frame_cb)
wl_callback_destroy(xwl_cursor->frame_cb);
}
static void
xwl_seat_update_cursor(struct xwl_cursor *xwl_cursor)
{
@ -1674,9 +1916,16 @@ tablet_tool_proximity_in(void *data, struct zwp_tablet_tool_v2 *tool,
if (wl_surface == NULL)
return;
if (!is_surface_from_xwl_window(wl_surface))
return;
xwl_tablet_tool->proximity_in_serial = serial;
xwl_seat->tablet_focus_window = wl_surface_get_user_data(wl_surface);
/* If there is a cursor surface frame callback pending, we need to clear it
* so that we can continue submitting new cursor frames.
*/
xwl_cursor_clear_frame_cb(&xwl_tablet_tool->cursor);
xwl_tablet_tool_set_cursor(xwl_tablet_tool);
}
@ -2268,7 +2517,7 @@ tablet_pad_group(void *data,
struct xwl_tablet_pad_group *group;
group = calloc(1, sizeof *group);
if (pad == NULL) {
if (group == NULL) {
ErrorF("%s ENOMEM\n", __func__);
return;
}
@ -2562,6 +2811,16 @@ init_pointer_constraints(struct xwl_screen *xwl_screen,
1);
}
static void
init_pointer_gestures(struct xwl_screen *xwl_screen,
uint32_t id, uint32_t version)
{
xwl_screen->pointer_gestures =
wl_registry_bind(xwl_screen->registry, id,
&zwp_pointer_gestures_v1_interface,
1);
}
static void
init_keyboard_grab(struct xwl_screen *xwl_screen,
uint32_t id, uint32_t version)
@ -2583,6 +2842,34 @@ init_keyboard_grab(struct xwl_screen *xwl_screen,
}
}
/* The compositor may send us wl_seat and its capabilities before sending e.g.
relative_pointer_manager or pointer_gesture interfaces. This would result in
devices being created in capabilities handler, but listeners not, because
the interfaces weren't available at the time. So we manually attempt to setup
listeners again.
*/
static void
maybe_init_relative_pointer_listeners_after_capabilities(struct xwl_screen* xwl_screen)
{
struct xwl_seat *xwl_seat;
xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) {
if (xwl_seat->wl_pointer) {
init_relative_pointer_listener(xwl_seat);
}
}
}
static void
maybe_init_pointer_gesture_listeners_after_capabilities(struct xwl_screen* xwl_screen)
{
struct xwl_seat *xwl_seat;
xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) {
if (xwl_seat->wl_pointer) {
init_pointer_gestures_listener(xwl_seat);
}
}
}
static void
input_handler(void *data, struct wl_registry *registry, uint32_t id,
const char *interface, uint32_t version)
@ -2594,8 +2881,12 @@ input_handler(void *data, struct wl_registry *registry, uint32_t id,
xwl_screen->expecting_event++;
} else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
init_relative_pointer_manager(xwl_screen, id, version);
maybe_init_relative_pointer_listeners_after_capabilities(xwl_screen);
} else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
init_pointer_constraints(xwl_screen, id, version);
} else if (strcmp(interface, "zwp_pointer_gestures_v1") == 0) {
init_pointer_gestures(xwl_screen, id, version);
maybe_init_pointer_gesture_listeners_after_capabilities(xwl_screen);
} else if (strcmp(interface, "zwp_tablet_manager_v2") == 0) {
init_tablet_manager(xwl_screen, id, version);
} else if (strcmp(interface, "zwp_xwayland_keyboard_grab_manager_v1") == 0) {
@ -2662,7 +2953,7 @@ sprite_check_lost_focus(SpritePtr sprite, WindowPtr window)
if (xwl_seat->focus_window == NULL &&
xwl_seat->last_xwindow != NullWindow &&
IsParent(xwl_seat->last_xwindow, window))
(IsParent(xwl_seat->last_xwindow, window) || xwl_seat->last_xwindow == window))
return TRUE;
return FALSE;

View File

@ -56,6 +56,7 @@ struct xwl_cursor {
struct xwl_seat {
DeviceIntPtr pointer;
DeviceIntPtr relative_pointer;
DeviceIntPtr pointer_gestures;
DeviceIntPtr keyboard;
DeviceIntPtr touch;
DeviceIntPtr stylus;
@ -65,6 +66,8 @@ struct xwl_seat {
struct wl_seat *seat;
struct wl_pointer *wl_pointer;
struct zwp_relative_pointer_v1 *wp_relative_pointer;
struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe;
struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch;
struct wl_keyboard *wl_keyboard;
struct wl_touch *wl_touch;
struct zwp_tablet_seat_v2 *tablet_seat;
@ -80,6 +83,10 @@ struct xwl_seat {
struct xwl_cursor cursor;
WindowPtr last_xwindow;
uint32_t pointer_gesture_swipe_fingers;
uint32_t pointer_gesture_pinch_fingers;
double pointer_gesture_pinch_last_scale;
struct xorg_list touches;
size_t keymap_size;

View File

@ -35,13 +35,6 @@
#include "xdg-output-unstable-v1-client-protocol.h"
#define ALL_ROTATIONS (RR_Rotate_0 | \
RR_Rotate_90 | \
RR_Rotate_180 | \
RR_Rotate_270 | \
RR_Reflect_X | \
RR_Reflect_Y)
static void xwl_output_get_xdg_output(struct xwl_output *xwl_output);
static Rotation
@ -216,6 +209,8 @@ update_screen_size(struct xwl_output *xwl_output, int width, int height)
}
update_desktop_dimensions();
RRTellChanged(xwl_screen->screen);
}
struct xwl_emulated_mode *
@ -466,6 +461,85 @@ xwl_output_set_randr_emu_props(struct xwl_screen *xwl_screen, ClientPtr client)
xwl_output_set_randr_emu_prop_callback, &prop);
}
static inline void
xwl_output_get_emulated_root_size(struct xwl_output *xwl_output,
ClientPtr client,
int *width,
int *height)
{
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
struct xwl_emulated_mode *emulated_mode;
emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client);
/* If not an emulated mode, just return the actual screen size */
if (!emulated_mode) {
*width = xwl_screen->width;
*height = xwl_screen->height;
return;
}
if (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) {
*width = emulated_mode->width;
*height = emulated_mode->height;
} else {
*width = emulated_mode->height;
*height = emulated_mode->width;
}
}
static int
xwl_output_get_rr_event_mask(WindowPtr pWin, ClientPtr client)
{
RREventPtr pRREvent, *pHead;
dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
RREventType, client, DixReadAccess);
pRREvent = NULL;
if (pHead) {
for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next)
if (pRREvent->client == client)
break;
}
if (pRREvent)
return pRREvent->mask;
return 0;
}
static void
xwl_output_notify_emulated_root_size(struct xwl_output *xwl_output,
ClientPtr client,
int new_emulated_root_width,
int new_emulated_root_height)
{
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
ScreenPtr pScreen = xwl_screen->screen;
WindowPtr pRoot = pScreen->root;
xEvent event = {
.u.configureNotify.event = pRoot->drawable.id,
.u.configureNotify.window = pRoot->drawable.id,
.u.configureNotify.aboveSibling = None,
.u.configureNotify.x = 0,
.u.configureNotify.y = 0,
.u.configureNotify.width = new_emulated_root_width,
.u.configureNotify.height = new_emulated_root_height,
.u.configureNotify.borderWidth = pRoot->borderWidth,
.u.configureNotify.override = pRoot->overrideRedirect
};
event.u.u.type = ConfigureNotify;
if (!client || client == serverClient || client->clientGone)
return;
if (EventMaskForClient(pRoot, client) & StructureNotifyMask)
WriteEventsToClient(client, 1, &event);
if (xwl_output_get_rr_event_mask(pRoot, client) & RRScreenChangeNotifyMask)
RRDeliverScreenEvent(client, pRoot, pScreen);
}
void
xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen,
WindowPtr window)
@ -480,10 +554,16 @@ void
xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
RRModePtr mode, Bool from_vidmode)
{
int old_emulated_width, old_emulated_height;
int new_emulated_width, new_emulated_height;
DebugF("XWAYLAND: xwl_output_set_emulated_mode from %s: %dx%d\n",
from_vidmode ? "vidmode" : "randr",
mode->mode.width, mode->mode.height);
xwl_output_get_emulated_root_size(xwl_output, client,
&old_emulated_width, &old_emulated_height);
/* modes[0] is the actual (not-emulated) output mode */
if (mode == xwl_output->randr_output->modes[0])
xwl_output_remove_emulated_mode_for_client(xwl_output, client);
@ -493,6 +573,15 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
xwl_screen_check_resolution_change_emulation(xwl_output->xwl_screen);
xwl_output_set_randr_emu_props(xwl_output->xwl_screen, client);
xwl_output_get_emulated_root_size(xwl_output, client,
&new_emulated_width, &new_emulated_height);
if (new_emulated_width != old_emulated_width ||
new_emulated_height != old_emulated_height)
xwl_output_notify_emulated_root_size(xwl_output, client,
new_emulated_width,
new_emulated_height);
}
static void
@ -631,11 +720,31 @@ static const struct zxdg_output_v1_listener xdg_output_listener = {
xdg_output_handle_description,
};
#define XRANDR_EMULATION_PROP "RANDR Emulation"
static Atom
get_rand_emulation_property(void)
{
const char *emulStr = XRANDR_EMULATION_PROP;
return MakeAtom(emulStr, strlen(emulStr), TRUE);
}
static void
xwl_output_set_emulated(struct xwl_output *xwl_output)
{
int32_t val = TRUE;
RRChangeOutputProperty(xwl_output->randr_output,
get_rand_emulation_property(),
XA_INTEGER,
32, PropModeReplace, 1,
&val, FALSE, FALSE);
}
struct xwl_output *
xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
{
struct xwl_output *xwl_output;
static int serial;
char name[256];
xwl_output = calloc(1, sizeof *xwl_output);
@ -654,7 +763,7 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
xwl_output->server_output_id = id;
wl_output_add_listener(xwl_output->output, &output_listener, xwl_output);
snprintf(name, sizeof name, "XWAYLAND%d", serial++);
snprintf(name, sizeof name, "XWAYLAND%d", xwl_get_next_output_serial());
xwl_output->xwl_screen = xwl_screen;
xwl_output->randr_crtc = RRCrtcCreate(xwl_screen->screen, xwl_output);
@ -670,10 +779,12 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
ErrorF("Failed creating RandR Output\n");
goto err;
}
xwl_output_set_emulated(xwl_output);
RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
RROutputSetConnection(xwl_output->randr_output, RR_Connected);
RRTellChanged(xwl_screen->screen);
/* We want the output to be in the list as soon as created so we can
* use it when binding to the xdg-output protocol...
@ -698,7 +809,12 @@ err:
void
xwl_output_destroy(struct xwl_output *xwl_output)
{
wl_output_destroy(xwl_output->output);
if (xwl_output->lease_connector)
wp_drm_lease_connector_v1_destroy(xwl_output->lease_connector);
if (xwl_output->xdg_output)
zxdg_output_v1_destroy(xwl_output->xdg_output);
if (xwl_output->output)
wl_output_destroy(xwl_output->output);
free(xwl_output);
}
@ -711,12 +827,15 @@ xwl_output_remove(struct xwl_output *xwl_output)
xorg_list_del(&xwl_output->link);
RROutputSetConnection(xwl_output->randr_output, RR_Disconnected);
xorg_list_for_each_entry(it, &xwl_screen->output_list, link)
output_get_new_size(it, &width, &height);
update_screen_size(xwl_output, width, height);
RRCrtcDestroy(xwl_output->randr_crtc);
RROutputDestroy(xwl_output->randr_output);
RRTellChanged(xwl_screen->screen);
xwl_output_destroy(xwl_output);
}
@ -801,6 +920,10 @@ xwl_randr_output_set_property(ScreenPtr pScreen,
Atom property,
RRPropertyValuePtr value)
{
/* RANDR Emulation property is read-only. */
if (get_rand_emulation_property() == property)
return FALSE;
return TRUE;
}
@ -846,6 +969,10 @@ xwl_screen_init_output(struct xwl_screen *xwl_screen)
rp->rrModeDestroy = xwl_randr_mode_destroy;
#endif
rp->rrRequestLease = xwl_randr_request_lease;
rp->rrGetLease = xwl_randr_get_lease;
rp->rrTerminateLease = xwl_randr_terminate_lease;
return TRUE;
}
@ -854,6 +981,12 @@ xwl_output_get_xdg_output(struct xwl_output *xwl_output)
{
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
if (!xwl_output->output) {
/* This can happen when an output is created from a leasable DRM
* connector */
return;
}
xwl_output->xdg_output =
zxdg_output_manager_v1_get_xdg_output (xwl_screen->xdg_output_manager,
xwl_output->output);
@ -873,3 +1006,10 @@ xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen)
xorg_list_for_each_entry(it, &xwl_screen->output_list, link)
xwl_output_get_xdg_output(it);
}
int
xwl_get_next_output_serial(void)
{
static int output_name_serial = 0;
return output_name_serial++;
}

View File

@ -34,19 +34,34 @@
#include <randrstr.h>
#include "xwayland-types.h"
#include "xwayland-drm-lease.h"
#define ALL_ROTATIONS (RR_Rotate_0 | \
RR_Rotate_90 | \
RR_Rotate_180 | \
RR_Rotate_270 | \
RR_Reflect_X | \
RR_Reflect_Y)
struct xwl_output {
struct xorg_list link;
struct wl_output *output;
struct zxdg_output_v1 *xdg_output;
uint32_t server_output_id;
struct xwl_screen *xwl_screen;
RROutputPtr randr_output;
RRCrtcPtr randr_crtc;
/* only for regular outputs */
struct wl_output *output;
struct zxdg_output_v1 *xdg_output;
uint32_t server_output_id;
int32_t x, y, width, height, refresh;
Rotation rotation;
Bool wl_output_done;
Bool xdg_output_done;
/* only for lease-able DRM connectors */
struct wp_drm_lease_connector_v1 *lease_connector;
struct xwl_drm_lease *lease;
struct xwl_drm_lease_device *lease_device;
};
/* Per client per output emulated randr/vidmode resolution info. */
@ -79,4 +94,6 @@ void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen,
void xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen);
int xwl_get_next_output_serial(void);
#endif /* XWAYLAND_OUTPUT_H */

View File

@ -34,6 +34,10 @@
#include "xwayland-pixmap.h"
#include "glamor.h"
#define XWL_PRESENT_CAPS PresentCapabilityAsync
/*
* When not flipping let Present copy with 60fps.
* When flipping wait on frame_callback, otherwise
@ -68,7 +72,8 @@ xwl_present_window_get_priv(WindowPtr window)
xorg_list_init(&xwl_present_window->frame_callback_list);
xorg_list_init(&xwl_present_window->wait_list);
xorg_list_init(&xwl_present_window->release_list);
xorg_list_init(&xwl_present_window->flip_queue);
xorg_list_init(&xwl_present_window->idle_queue);
dixSetPrivate(&window->devPrivates,
&xwl_present_window_private_key,
@ -78,11 +83,18 @@ xwl_present_window_get_priv(WindowPtr window)
return xwl_present_window;
}
static struct xwl_present_event *
xwl_present_event_from_id(uint64_t event_id)
{
return (struct xwl_present_event*)(uintptr_t)event_id;
}
static void
xwl_present_free_timer(struct xwl_present_window *xwl_present_window)
{
TimerFree(xwl_present_window->frame_timer);
xwl_present_window->frame_timer = NULL;
xwl_present_window->timer_armed = 0;
}
static CARD32
@ -90,24 +102,61 @@ xwl_present_timer_callback(OsTimerPtr timer,
CARD32 time,
void *arg);
static present_vblank_ptr
xwl_present_get_pending_flip(struct xwl_present_window *xwl_present_window)
{
present_vblank_ptr flip_pending;
if (xorg_list_is_empty(&xwl_present_window->flip_queue))
return NULL;
flip_pending = xorg_list_first_entry(&xwl_present_window->flip_queue, present_vblank_rec,
event_queue);
if (flip_pending->queued)
return NULL;
return flip_pending;
}
static inline Bool
xwl_present_has_pending_events(struct xwl_present_window *xwl_present_window)
{
return !!xwl_present_window->sync_flip ||
present_vblank_ptr flip_pending = xwl_present_get_pending_flip(xwl_present_window);
return (flip_pending && flip_pending->sync_flip) ||
!xorg_list_is_empty(&xwl_present_window->wait_list);
}
static void
void
xwl_present_reset_timer(struct xwl_present_window *xwl_present_window)
{
if (xwl_present_has_pending_events(xwl_present_window)) {
struct xwl_window *xwl_window = xwl_window_from_window(xwl_present_window->window);
CARD32 now = GetTimeInMillis();
CARD32 timeout;
if (!xorg_list_is_empty(&xwl_present_window->frame_callback_list))
if (xwl_window && xwl_window->frame_callback &&
!xorg_list_is_empty(&xwl_present_window->frame_callback_list))
timeout = TIMER_LEN_FLIP;
else
timeout = TIMER_LEN_COPY;
/* Make sure the timer callback runs if at least a second has passed
* since we first armed the timer. This can happen e.g. if the Wayland
* compositor doesn't send a pending frame event, e.g. because the
* Wayland surface isn't visible anywhere.
*/
if (xwl_present_window->timer_armed) {
if ((int)(now - xwl_present_window->timer_armed) > 1000) {
xwl_present_timer_callback(xwl_present_window->frame_timer, now,
xwl_present_window);
return;
}
} else {
xwl_present_window->timer_armed = now;
}
xwl_present_window->frame_timer = TimerSet(xwl_present_window->frame_timer,
0, timeout,
&xwl_present_timer_callback,
@ -117,6 +166,58 @@ xwl_present_reset_timer(struct xwl_present_window *xwl_present_window)
}
}
static void
xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
static uint32_t
xwl_present_query_capabilities(present_screen_priv_ptr screen_priv)
{
return XWL_PRESENT_CAPS;
}
static int
xwl_present_get_ust_msc(ScreenPtr screen,
WindowPtr present_window,
uint64_t *ust,
uint64_t *msc)
{
struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
if (!xwl_present_window)
return BadAlloc;
*ust = xwl_present_window->ust;
*msc = xwl_present_window->msc;
return Success;
}
/*
* When the wait fence or previous flip is completed, it's time
* to re-try the request
*/
static void
xwl_present_re_execute(present_vblank_ptr vblank)
{
uint64_t ust = 0, crtc_msc = 0;
(void) xwl_present_get_ust_msc(vblank->screen, vblank->window, &ust, &crtc_msc);
xwl_present_execute(vblank, ust, crtc_msc);
}
static void
xwl_present_flip_try_ready(struct xwl_present_window *xwl_present_window)
{
present_vblank_ptr vblank;
xorg_list_for_each_entry(vblank, &xwl_present_window->flip_queue, event_queue) {
if (vblank->queued) {
xwl_present_re_execute(vblank);
return;
}
}
}
static void
xwl_present_release_pixmap(struct xwl_present_event *event)
{
@ -131,18 +232,131 @@ xwl_present_release_pixmap(struct xwl_present_event *event)
static void
xwl_present_free_event(struct xwl_present_event *event)
{
if (!event)
xwl_present_release_pixmap(event);
xorg_list_del(&event->vblank.event_queue);
present_vblank_destroy(&event->vblank);
}
static void
xwl_present_free_idle_vblank(present_vblank_ptr vblank)
{
present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
xwl_present_free_event(xwl_present_event_from_id((uintptr_t)vblank));
}
static WindowPtr
xwl_present_toplvl_pixmap_window(WindowPtr window)
{
ScreenPtr screen = window->drawable.pScreen;
PixmapPtr pixmap = (*screen->GetWindowPixmap)(window);
WindowPtr w = window;
WindowPtr next_w;
while(w->parent) {
next_w = w->parent;
if ( (*screen->GetWindowPixmap)(next_w) != pixmap) {
break;
}
w = next_w;
}
return w;
}
static void
xwl_present_flips_stop(WindowPtr window)
{
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
present_vblank_ptr vblank, tmp;
/* Change back to the fast refresh rate */
xwl_present_reset_timer(xwl_present_window);
/* Free any left over idle vblanks */
xorg_list_for_each_entry_safe(vblank, tmp, &xwl_present_window->idle_queue, event_queue)
xwl_present_free_idle_vblank(vblank);
if (xwl_present_window->flip_active) {
struct xwl_present_event *event;
vblank = xwl_present_window->flip_active;
event = xwl_present_event_from_id((uintptr_t)vblank);
if (event->pixmap)
xwl_present_free_idle_vblank(vblank);
else
xwl_present_free_event(event);
xwl_present_window->flip_active = NULL;
}
xwl_present_flip_try_ready(xwl_present_window);
}
static void
xwl_present_flip_notify_vblank(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
{
WindowPtr window = vblank->window;
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
DebugPresent(("\tn %" PRIu64 " %p %" PRIu64 " %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
vblank->event_id, vblank, vblank->exec_msc, vblank->target_msc,
vblank->pixmap ? vblank->pixmap->drawable.id : 0,
vblank->window ? vblank->window->drawable.id : 0));
assert (&vblank->event_queue == xwl_present_window->flip_queue.next);
xorg_list_del(&vblank->event_queue);
if (xwl_present_window->flip_active) {
struct xwl_present_event *event =
xwl_present_event_from_id((uintptr_t)xwl_present_window->flip_active);
if (!event->pixmap)
xwl_present_free_event(event);
else
/* Put the previous flip in the idle_queue and wait for further notice from
* the Wayland compositor
*/
xorg_list_append(&xwl_present_window->flip_active->event_queue, &xwl_present_window->idle_queue);
}
xwl_present_window->flip_active = vblank;
present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc);
if (vblank->abort_flip)
xwl_present_flips_stop(window);
xwl_present_flip_try_ready(xwl_present_window);
}
static void
xwl_present_update_window_crtc(present_window_priv_ptr window_priv, RRCrtcPtr crtc, uint64_t new_msc)
{
/* Crtc unchanged, no offset. */
if (crtc == window_priv->crtc)
return;
xwl_present_release_pixmap(event);
xorg_list_del(&event->list);
free(event);
/* No crtc earlier to offset against, just set the crtc. */
if (window_priv->crtc == PresentCrtcNeverSet) {
window_priv->msc_offset = 0;
window_priv->crtc = crtc;
return;
}
/* In window-mode the last correct msc-offset is always kept
* in window-priv struct because msc is saved per window and
* not per crtc as in screen-mode.
*/
window_priv->msc_offset += new_msc - window_priv->msc;
window_priv->crtc = crtc;
}
void
xwl_present_cleanup(WindowPtr window)
{
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
present_window_priv_ptr window_priv = present_window_priv(window);
struct xwl_present_event *event, *tmp;
if (!xwl_present_window)
@ -156,12 +370,7 @@ xwl_present_cleanup(WindowPtr window)
}
/* Clear remaining events */
xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->wait_list, list)
xwl_present_free_event(event);
xwl_present_free_event(xwl_present_window->sync_flip);
xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->release_list, list)
xorg_list_for_each_entry_safe(event, tmp, &window_priv->vblank, vblank.window_list)
xwl_present_free_event(event);
/* Clear timer */
@ -178,53 +387,44 @@ xwl_present_cleanup(WindowPtr window)
static void
xwl_present_buffer_release(void *data)
{
struct xwl_present_window *xwl_present_window;
struct xwl_present_event *event = data;
present_vblank_ptr vblank;
if (!event)
return;
xwl_present_release_pixmap(event);
vblank = &event->vblank;
present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
if (!event->abort)
present_wnmd_idle_notify(event->xwl_present_window->window, event->event_id);
if (!event->pending)
xwl_present_window = xwl_present_window_priv(vblank->window);
if (xwl_present_window->flip_active == vblank ||
xwl_present_get_pending_flip(xwl_present_window) == vblank)
xwl_present_release_pixmap(event);
else
xwl_present_free_event(event);
}
static void
xwl_present_msc_bump(struct xwl_present_window *xwl_present_window)
{
present_vblank_ptr flip_pending = xwl_present_get_pending_flip(xwl_present_window);
uint64_t msc = ++xwl_present_window->msc;
struct xwl_present_event *event, *tmp;
present_vblank_ptr vblank, tmp;
xwl_present_window->ust = GetTimeInMicros();
event = xwl_present_window->sync_flip;
xwl_present_window->sync_flip = NULL;
if (event) {
event->pending = FALSE;
xwl_present_window->timer_armed = 0;
present_wnmd_flip_notify(xwl_present_window->window, event->event_id,
xwl_present_window->ust, msc);
if (flip_pending && flip_pending->sync_flip)
xwl_present_flip_notify_vblank(flip_pending, xwl_present_window->ust, msc);
if (!event->pixmap) {
/* If the buffer was already released, clean up now */
xwl_present_free_event(event);
} else {
xorg_list_add(&event->list, &xwl_present_window->release_list);
}
}
xorg_list_for_each_entry_safe(vblank, tmp, &xwl_present_window->wait_list, event_queue) {
if (vblank->exec_msc <= msc) {
DebugPresent(("\te %" PRIu64 " ust %" PRIu64 " msc %" PRIu64 "\n",
vblank->event_id, xwl_present_window->ust, msc));
xorg_list_for_each_entry_safe(event, tmp,
&xwl_present_window->wait_list,
list) {
if (event->target_msc <= msc) {
present_wnmd_event_notify(xwl_present_window->window,
event->event_id,
xwl_present_window->ust,
msc);
xwl_present_free_event(event);
xwl_present_execute(vblank, xwl_present_window->ust, msc);
}
}
}
@ -265,20 +465,13 @@ xwl_present_sync_callback(void *data,
struct wl_callback *callback,
uint32_t time)
{
struct xwl_present_event *event = data;
struct xwl_present_window *xwl_present_window = event->xwl_present_window;
present_vblank_ptr vblank = data;
struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(vblank->window);
wl_callback_destroy(xwl_present_window->sync_callback);
xwl_present_window->sync_callback = NULL;
event->pending = FALSE;
if (!event->abort)
present_wnmd_flip_notify(xwl_present_window->window, event->event_id,
xwl_present_window->ust, xwl_present_window->msc);
if (!event->pixmap)
xwl_present_free_event(event);
xwl_present_flip_notify_vblank(vblank, xwl_present_window->ust, xwl_present_window->msc);
}
static const struct wl_callback_listener xwl_present_sync_listener = {
@ -286,7 +479,8 @@ static const struct wl_callback_listener xwl_present_sync_listener = {
};
static RRCrtcPtr
xwl_present_get_crtc(WindowPtr present_window)
xwl_present_get_crtc(present_screen_priv_ptr screen_priv,
WindowPtr present_window)
{
struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
rrScrPrivPtr rr_private;
@ -302,46 +496,28 @@ xwl_present_get_crtc(WindowPtr present_window)
return rr_private->crtcs[0];
}
static int
xwl_present_get_ust_msc(WindowPtr present_window, uint64_t *ust, uint64_t *msc)
{
struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
if (!xwl_present_window)
return BadAlloc;
*ust = xwl_present_window->ust;
*msc = xwl_present_window->msc;
return Success;
}
/*
* Queue an event to report back to the Present extension when the specified
* MSC has past
* MSC has passed
*/
static int
xwl_present_queue_vblank(WindowPtr present_window,
xwl_present_queue_vblank(ScreenPtr screen,
WindowPtr present_window,
RRCrtcPtr crtc,
uint64_t event_id,
uint64_t msc)
{
struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
struct xwl_window *xwl_window = xwl_window_from_window(present_window);
struct xwl_present_event *event;
struct xwl_present_event *event = xwl_present_event_from_id(event_id);
event = malloc(sizeof *event);
if (!event)
return BadAlloc;
event->vblank.exec_msc = msc;
event->event_id = event_id;
event->pixmap = NULL;
event->xwl_present_window = xwl_present_window;
event->target_msc = msc;
xorg_list_del(&event->vblank.event_queue);
xorg_list_append(&event->vblank.event_queue, &xwl_present_window->wait_list);
xorg_list_append(&event->list, &xwl_present_window->wait_list);
/* If there's a pending frame callback, use that */
if (xwl_window && xwl_window->frame_callback &&
/* Hook up to frame callback */
if (xwl_window &&
xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
xorg_list_add(&xwl_present_window->frame_callback_list,
&xwl_window->frame_callback_list);
@ -359,30 +535,22 @@ xwl_present_queue_vblank(WindowPtr present_window,
* to the extension
*/
static void
xwl_present_abort_vblank(WindowPtr present_window,
xwl_present_abort_vblank(ScreenPtr screen,
WindowPtr present_window,
RRCrtcPtr crtc,
uint64_t event_id,
uint64_t msc)
{
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(present_window);
struct xwl_present_event *event, *tmp;
static Bool called;
if (!xwl_present_window)
if (called)
return;
xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->wait_list, list) {
if (event->event_id == event_id) {
xwl_present_free_event(event);
return;
}
}
xorg_list_for_each_entry(event, &xwl_present_window->release_list, list) {
if (event->event_id == event_id) {
event->abort = TRUE;
return;
}
}
/* xwl_present_cleanup should have cleaned up everything,
* present_free_window_vblank shouldn't need to call this.
*/
ErrorF("Unexpected call to %s:\n", __func__);
xorg_backtrace();
}
static void
@ -392,18 +560,52 @@ xwl_present_flush(WindowPtr window)
}
static Bool
xwl_present_check_flip2(RRCrtcPtr crtc,
WindowPtr present_window,
PixmapPtr pixmap,
Bool sync_flip,
PresentFlipReason *reason)
xwl_present_check_flip(RRCrtcPtr crtc,
WindowPtr present_window,
PixmapPtr pixmap,
Bool sync_flip,
RegionPtr valid,
int16_t x_off,
int16_t y_off,
PresentFlipReason *reason)
{
WindowPtr toplvl_window = xwl_present_toplvl_pixmap_window(present_window);
struct xwl_window *xwl_window = xwl_window_from_window(present_window);
ScreenPtr screen = pixmap->drawable.pScreen;
if (reason)
*reason = PRESENT_FLIP_REASON_UNKNOWN;
if (!xwl_window)
return FALSE;
if (!crtc)
return FALSE;
/* Source pixmap must align with window exactly */
if (x_off || y_off)
return FALSE;
/* Valid area must contain window (for simplicity for now just never flip when one is set). */
if (valid)
return FALSE;
/* Flip pixmap must have same dimensions as window */
if (present_window->drawable.width != pixmap->drawable.width ||
present_window->drawable.height != pixmap->drawable.height)
return FALSE;
/* Window must be same region as toplevel window */
if ( !RegionEqual(&present_window->winSize, &toplvl_window->winSize) )
return FALSE;
/* Can't flip if window clipped by children */
if (!RegionEqual(&present_window->clipList, &present_window->winSize))
return FALSE;
if (!xwl_glamor_check_flip(pixmap))
return FALSE;
/* Can't flip if the window pixmap doesn't match the xwl_window parent
* window's, e.g. because a client redirected this window or one of its
* parents.
@ -422,11 +624,63 @@ xwl_present_check_flip2(RRCrtcPtr crtc,
return TRUE;
}
/*
* 'window' is being reconfigured. Check to see if it is involved
* in flipping and clean up as necessary.
*/
static void
xwl_present_check_flip_window (WindowPtr window)
{
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
present_window_priv_ptr window_priv = present_window_priv(window);
present_vblank_ptr flip_pending;
present_vblank_ptr flip_active;
present_vblank_ptr vblank;
PresentFlipReason reason;
/* If this window hasn't ever been used with Present, it can't be
* flipping
*/
if (!xwl_present_window || !window_priv)
return;
flip_pending = xwl_present_get_pending_flip(xwl_present_window);
flip_active = xwl_present_window->flip_active;
if (flip_pending) {
if (!xwl_present_check_flip(flip_pending->crtc, flip_pending->window, flip_pending->pixmap,
flip_pending->sync_flip, flip_pending->valid, 0, 0, NULL))
flip_pending->abort_flip = TRUE;
} else if (flip_active) {
if (!xwl_present_check_flip(flip_active->crtc, flip_active->window, flip_active->pixmap,
flip_active->sync_flip, flip_active->valid, 0, 0, NULL))
xwl_present_flips_stop(window);
}
/* Now check any queued vblanks */
xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
if (vblank->queued && vblank->flip &&
!xwl_present_check_flip(vblank->crtc, window, vblank->pixmap,
vblank->sync_flip, vblank->valid, 0, 0, &reason)) {
vblank->flip = FALSE;
vblank->reason = reason;
}
}
}
/*
* Clean up any pending or current flips for this window
*/
static void
xwl_present_clear_window_flip(WindowPtr window)
{
/* xwl_present_cleanup cleaned up everything */
}
static Bool
xwl_present_flip(WindowPtr present_window,
RRCrtcPtr crtc,
uint64_t event_id,
uint64_t target_msc,
PixmapPtr pixmap,
Bool sync_flip,
RegionPtr damage)
@ -435,49 +689,35 @@ xwl_present_flip(WindowPtr present_window,
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(present_window);
BoxPtr damage_box;
struct wl_buffer *buffer;
struct xwl_present_event *event;
struct xwl_present_event *event = xwl_present_event_from_id(event_id);
if (!xwl_window)
return FALSE;
buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap);
if (!buffer) {
ErrorF("present: Error getting buffer\n");
return FALSE;
}
damage_box = RegionExtents(damage);
event = malloc(sizeof *event);
if (!event)
return FALSE;
pixmap->refcnt++;
buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap);
event->event_id = event_id;
event->xwl_present_window = xwl_present_window;
event->pixmap = pixmap;
event->target_msc = target_msc;
event->pending = TRUE;
event->abort = FALSE;
if (sync_flip) {
xorg_list_init(&event->list);
xwl_present_window->sync_flip = event;
} else {
xorg_list_add(&event->list, &xwl_present_window->release_list);
}
xwl_pixmap_set_buffer_release_cb(pixmap, xwl_present_buffer_release, event);
/* We can flip directly to the main surface (full screen window without clips) */
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
if (!xwl_window->frame_callback)
xwl_window_create_frame_callback(xwl_window);
if (xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
xorg_list_add(&xwl_present_window->frame_callback_list,
&xwl_window->frame_callback_list);
}
/* Realign timer */
xwl_present_reset_timer(xwl_present_window);
if (!xwl_window->frame_callback)
xwl_window_create_frame_callback(xwl_window);
xwl_surface_damage(xwl_window->xwl_screen, xwl_window->surface,
damage_box->x1 - present_window->drawable.x,
@ -492,7 +732,7 @@ xwl_present_flip(WindowPtr present_window,
wl_display_sync(xwl_window->xwl_screen->display);
wl_callback_add_listener(xwl_present_window->sync_callback,
&xwl_present_sync_listener,
event);
&event->vblank);
}
wl_display_flush(xwl_window->xwl_screen->display);
@ -500,13 +740,210 @@ xwl_present_flip(WindowPtr present_window,
return TRUE;
}
/*
* Once the required MSC has been reached, execute the pending request.
*
* For requests to actually present something, either blt contents to
* the window pixmap or queue a window buffer swap on the backend.
*
* For requests to just get the current MSC/UST combo, skip that part and
* go straight to event delivery.
*/
static void
xwl_present_flips_stop(WindowPtr window)
xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
{
struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
WindowPtr window = vblank->window;
struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window);
present_vblank_ptr flip_pending = xwl_present_get_pending_flip(xwl_present_window);
/* Change back to the fast refresh rate */
xwl_present_reset_timer(xwl_present_window);
xorg_list_del(&vblank->event_queue);
if (present_execute_wait(vblank, crtc_msc))
return;
if (flip_pending && vblank->flip && vblank->pixmap && vblank->window) {
DebugPresent(("\tr %" PRIu64 " %p (pending %p)\n",
vblank->event_id, vblank, flip_pending));
xorg_list_append(&vblank->event_queue, &xwl_present_window->flip_queue);
vblank->flip_ready = TRUE;
return;
}
vblank->queued = FALSE;
if (vblank->pixmap && vblank->window) {
ScreenPtr screen = window->drawable.pScreen;
if (vblank->flip) {
RegionPtr damage;
DebugPresent(("\tf %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
vblank->event_id, vblank, crtc_msc,
vblank->pixmap->drawable.id, vblank->window->drawable.id));
/* Set update region as damaged */
if (vblank->update) {
damage = RegionDuplicate(vblank->update);
/* Translate update region to screen space */
assert(vblank->x_off == 0 && vblank->y_off == 0);
RegionTranslate(damage, window->drawable.x, window->drawable.y);
RegionIntersect(damage, damage, &window->clipList);
} else
damage = RegionDuplicate(&window->clipList);
if (xwl_present_flip(vblank->window, vblank->crtc, vblank->event_id,
vblank->pixmap, vblank->sync_flip, damage)) {
WindowPtr toplvl_window = xwl_present_toplvl_pixmap_window(vblank->window);
PixmapPtr old_pixmap = screen->GetWindowPixmap(window);
/* Replace window pixmap with flip pixmap */
#ifdef COMPOSITE
vblank->pixmap->screen_x = old_pixmap->screen_x;
vblank->pixmap->screen_y = old_pixmap->screen_y;
#endif
present_set_tree_pixmap(toplvl_window, old_pixmap, vblank->pixmap);
vblank->pixmap->refcnt++;
dixDestroyPixmap(old_pixmap, old_pixmap->drawable.id);
/* Report damage */
DamageDamageRegion(&vblank->window->drawable, damage);
RegionDestroy(damage);
/* Put pending flip at the flip queue head */
xorg_list_add(&vblank->event_queue, &xwl_present_window->flip_queue);
/* Realign timer */
xwl_present_reset_timer(xwl_present_window);
return;
}
vblank->flip = FALSE;
}
DebugPresent(("\tc %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
if (flip_pending)
flip_pending->abort_flip = TRUE;
else if (xwl_present_window->flip_active)
xwl_present_flips_stop(window);
present_execute_copy(vblank, crtc_msc);
assert(!vblank->queued);
/* Clear the pixmap field, so this will fall through to present_execute_post next time */
dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
vblank->pixmap = NULL;
if (xwl_present_queue_vblank(screen, window, vblank->crtc,
vblank->event_id, crtc_msc + 1)
== Success)
return;
}
present_execute_post(vblank, ust, crtc_msc);
}
static int
xwl_present_pixmap(WindowPtr window,
PixmapPtr pixmap,
CARD32 serial,
RegionPtr valid,
RegionPtr update,
int16_t x_off,
int16_t y_off,
RRCrtcPtr target_crtc,
SyncFence *wait_fence,
SyncFence *idle_fence,
uint32_t options,
uint64_t target_window_msc,
uint64_t divisor,
uint64_t remainder,
present_notify_ptr notifies,
int num_notifies)
{
uint64_t ust = 0;
uint64_t target_msc;
uint64_t crtc_msc = 0;
int ret;
present_vblank_ptr vblank, tmp;
ScreenPtr screen = window->drawable.pScreen;
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
struct xwl_present_event *event;
if (!window_priv)
return BadAlloc;
target_crtc = xwl_present_get_crtc(screen_priv, window);
ret = xwl_present_get_ust_msc(screen, window, &ust, &crtc_msc);
xwl_present_update_window_crtc(window_priv, target_crtc, crtc_msc);
if (ret == Success) {
/* Stash the current MSC away in case we need it later
*/
window_priv->msc = crtc_msc;
}
target_msc = present_get_target_msc(target_window_msc + window_priv->msc_offset,
crtc_msc,
divisor,
remainder,
options);
/*
* Look for a matching presentation already on the list...
*/
if (!update && pixmap) {
xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
if (!vblank->pixmap)
continue;
if (!vblank->queued)
continue;
if (vblank->target_msc != target_msc)
continue;
present_vblank_scrap(vblank);
if (vblank->flip_ready)
xwl_present_re_execute(vblank);
}
}
event = calloc(1, sizeof(*event));
if (!event)
return BadAlloc;
vblank = &event->vblank;
if (!present_vblank_init(vblank, window, pixmap, serial, valid, update, x_off, y_off,
target_crtc, wait_fence, idle_fence, options, XWL_PRESENT_CAPS,
notifies, num_notifies, target_msc, crtc_msc)) {
present_vblank_destroy(vblank);
return BadAlloc;
}
vblank->event_id = (uintptr_t)event;
/* Xwayland presentations always complete (at least) one frame after they
* are executed
*/
vblank->exec_msc = vblank->target_msc - 1;
vblank->queued = TRUE;
if (crtc_msc < vblank->exec_msc) {
if (xwl_present_queue_vblank(screen, window, target_crtc, vblank->event_id, vblank->exec_msc) == Success)
return Success;
DebugPresent(("present_queue_vblank failed\n"));
}
xwl_present_execute(vblank, ust, crtc_msc);
return Success;
}
void
@ -516,35 +953,47 @@ xwl_present_unrealize_window(struct xwl_present_window *xwl_present_window)
* the frame timer interval.
*/
xorg_list_del(&xwl_present_window->frame_callback_list);
/* Make sure the timer callback doesn't get called */
xwl_present_window->timer_armed = 0;
xwl_present_reset_timer(xwl_present_window);
}
static present_wnmd_info_rec xwl_present_info = {
.version = PRESENT_SCREEN_INFO_VERSION,
.get_crtc = xwl_present_get_crtc,
.get_ust_msc = xwl_present_get_ust_msc,
.queue_vblank = xwl_present_queue_vblank,
.abort_vblank = xwl_present_abort_vblank,
.flush = xwl_present_flush,
.capabilities = PresentCapabilityAsync,
.check_flip2 = xwl_present_check_flip2,
.flip = xwl_present_flip,
.flips_stop = xwl_present_flips_stop
};
Bool
xwl_present_init(ScreenPtr screen)
{
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
present_screen_priv_ptr screen_priv;
if (!xwl_glamor_has_present_flip(xwl_screen))
if (!xwl_screen->glamor || !xwl_screen->egl_backend)
return FALSE;
if (!present_screen_register_priv_keys())
return FALSE;
if (present_screen_priv(screen))
return TRUE;
screen_priv = present_screen_priv_init(screen);
if (!screen_priv)
return FALSE;
if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0))
return FALSE;
return present_wnmd_screen_init(screen, &xwl_present_info);
screen_priv->query_capabilities = xwl_present_query_capabilities;
screen_priv->get_crtc = xwl_present_get_crtc;
screen_priv->check_flip = xwl_present_check_flip;
screen_priv->check_flip_window = xwl_present_check_flip_window;
screen_priv->clear_window_flip = xwl_present_clear_window_flip;
screen_priv->present_pixmap = xwl_present_pixmap;
screen_priv->queue_vblank = xwl_present_queue_vblank;
screen_priv->flush = xwl_present_flush;
screen_priv->re_execute = xwl_present_re_execute;
screen_priv->abort_vblank = xwl_present_abort_vblank;
return TRUE;
}

View File

@ -29,39 +29,39 @@
#include <xwayland-config.h>
#include <dix.h>
#include <present_priv.h>
#include "xwayland-types.h"
#ifdef GLAMOR_HAS_GBM
struct xwl_present_window {
struct xwl_present_event *sync_flip;
WindowPtr window;
struct xorg_list frame_callback_list;
uint64_t msc;
uint64_t ust;
OsTimerPtr frame_timer;
/* Timestamp when the current timer was first armed */
CARD32 timer_armed;
struct wl_callback *sync_callback;
struct xorg_list wait_list;
struct xorg_list release_list;
struct xorg_list flip_queue;
struct xorg_list idle_queue;
present_vblank_ptr flip_active;
};
struct xwl_present_event {
uint64_t event_id;
uint64_t target_msc;
present_vblank_rec vblank;
Bool abort;
Bool pending;
struct xwl_present_window *xwl_present_window;
PixmapPtr pixmap;
struct xorg_list list;
};
void xwl_present_reset_timer(struct xwl_present_window *xwl_present_window);
void xwl_present_frame_callback(struct xwl_present_window *xwl_present_window);
Bool xwl_present_init(ScreenPtr screen);
void xwl_present_cleanup(WindowPtr window);

View File

@ -52,6 +52,10 @@
#include "xwayland-present.h"
#include "xwayland-shm.h"
#ifdef MITSHM
#include "shmint.h"
#endif
#include "xdg-output-unstable-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "xdg-shell-client-protocol.h"
@ -145,12 +149,31 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure,
xwl_window_update_property(xwl_window, rec);
}
static void
xwl_root_window_finalized_callback(CallbackListPtr *pcbl,
void *closure,
void *calldata)
{
ScreenPtr screen = closure;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
struct xwl_queued_drm_lease_device *queued_device, *next;
xorg_list_for_each_entry_safe(queued_device, next,
&xwl_screen->queued_drm_lease_devices, link) {
xwl_screen_add_drm_lease_device(xwl_screen, queued_device->id);
xorg_list_del(&queued_device->link);
free(queued_device);
}
DeleteCallback(&RootWindowFinalizeCallback, xwl_root_window_finalized_callback, screen);
}
Bool
xwl_close_screen(ScreenPtr screen)
{
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
struct xwl_output *xwl_output, *next_xwl_output;
struct xwl_seat *xwl_seat, *next_xwl_seat;
struct xwl_wl_surface *xwl_wl_surface, *xwl_wl_surface_next;
DeleteCallback(&PropertyStateCallback, xwl_property_callback, screen);
@ -164,6 +187,16 @@ xwl_close_screen(ScreenPtr screen)
xwl_screen_release_tablet_manager(xwl_screen);
struct xwl_drm_lease_device *device_data, *next;
xorg_list_for_each_entry_safe(device_data, next,
&xwl_screen->drm_lease_devices, link)
xwl_screen_destroy_drm_lease_device(xwl_screen,
device_data->drm_lease_device);
xorg_list_for_each_entry_safe(xwl_wl_surface, xwl_wl_surface_next,
&xwl_screen->pending_wl_surface_destroy, link)
xwl_window_surface_do_destroy(xwl_wl_surface);
RemoveNotifyFd(xwl_screen->wayland_fd);
wl_display_disconnect(xwl_screen->display);
@ -388,6 +421,15 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, version);
xwl_screen_init_xdg_output(xwl_screen);
}
else if (strcmp(interface, "wp_drm_lease_device_v1") == 0) {
if (xwl_screen->screen->root == NULL) {
struct xwl_queued_drm_lease_device *queued = malloc(sizeof(struct xwl_queued_drm_lease_device));
queued->id = id;
xorg_list_append(&queued->link, &xwl_screen->queued_drm_lease_devices);
} else {
xwl_screen_add_drm_lease_device(xwl_screen, id);
}
}
else if (strcmp(interface, "wp_viewporter") == 0) {
xwl_screen->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1);
}
@ -404,6 +446,7 @@ global_remove(void *data, struct wl_registry *registry, uint32_t name)
{
struct xwl_screen *xwl_screen = data;
struct xwl_output *xwl_output, *tmp_xwl_output;
struct xwl_drm_lease_device *lease_device, *tmp_lease_device;
xorg_list_for_each_entry_safe(xwl_output, tmp_xwl_output,
&xwl_screen->output_list, link) {
@ -412,6 +455,14 @@ global_remove(void *data, struct wl_registry *registry, uint32_t name)
break;
}
}
xorg_list_for_each_entry_safe(lease_device, tmp_lease_device,
&xwl_screen->drm_lease_devices, link) {
if (lease_device->id == name) {
wp_drm_lease_device_v1_release(lease_device->drm_lease_device);
break;
}
}
}
static const struct wl_registry_listener registry_listener = {
@ -471,13 +522,13 @@ xwl_dispatch_events (struct xwl_screen *xwl_screen)
pollout:
ready = xwl_display_pollout(xwl_screen, 5);
if (ready == -1 && errno != EINTR)
xwl_give_up("error polling on XWayland fd: %s\n", strerror(errno));
xwl_give_up("error polling on Xwayland fd: %s\n", strerror(errno));
if (ready > 0)
ret = wl_display_flush(xwl_screen->display);
if (ret == -1 && errno != EAGAIN)
xwl_give_up("failed to write to XWayland fd: %s\n", strerror(errno));
xwl_give_up("failed to write to Xwayland fd: %s\n", strerror(errno));
xwl_screen->wait_flush = (ready == 0 || ready == -1 || ret == -1);
}
@ -534,6 +585,53 @@ xwl_screen_roundtrip(struct xwl_screen *xwl_screen)
xwl_give_up("could not connect to wayland server\n");
}
static int
xwl_server_grab(ClientPtr client)
{
struct xwl_screen *xwl_screen;
/* Allow GrabServer for the X11 window manager.
* Xwayland only has 1 screen (no Zaphod for Xwayland) so we check
* for the first and only screen here.
*/
xwl_screen = xwl_screen_get(screenInfo.screens[0]);
if (xwl_screen->wm_client_id == client->index)
return xwl_screen->GrabServer(client);
/* For all other clients, just pretend it works for compatibility,
but do nothing */
return Success;
}
static int
xwl_server_ungrab(ClientPtr client)
{
struct xwl_screen *xwl_screen;
/* Same as above, allow UngrabServer for the X11 window manager only */
xwl_screen = xwl_screen_get(screenInfo.screens[0]);
if (xwl_screen->wm_client_id == client->index)
return xwl_screen->UngrabServer(client);
/* For all other clients, just pretend it works for compatibility,
but do nothing */
return Success;
}
static void
xwl_screen_setup_custom_vector(struct xwl_screen *xwl_screen)
{
/* Rootfull Xwayland does not need a custom ProcVector (yet?) */
if (!xwl_screen->rootless)
return;
xwl_screen->GrabServer = ProcVector[X_GrabServer];
xwl_screen->UngrabServer = ProcVector[X_UngrabServer];
ProcVector[X_GrabServer] = xwl_server_grab;
ProcVector[X_UngrabServer] = xwl_server_ungrab;
}
Bool
xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
{
@ -545,10 +643,6 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
Bool use_eglstreams = FALSE;
#endif
xwl_screen = calloc(1, sizeof *xwl_screen);
if (xwl_screen == NULL)
return FALSE;
if (!dixRegisterPrivateKey(&xwl_screen_private_key, PRIVATE_SCREEN, 0))
return FALSE;
if (!xwl_pixmap_init())
@ -563,6 +657,10 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
sizeof(struct xwl_client)))
return FALSE;
xwl_screen = calloc(1, sizeof *xwl_screen);
if (xwl_screen == NULL)
return FALSE;
dixSetPrivate(&pScreen->devPrivates, &xwl_screen_private_key, xwl_screen);
xwl_screen->screen = pScreen;
@ -615,6 +713,10 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
xorg_list_init(&xwl_screen->seat_list);
xorg_list_init(&xwl_screen->damage_window_list);
xorg_list_init(&xwl_screen->window_list);
xorg_list_init(&xwl_screen->drm_lease_devices);
xorg_list_init(&xwl_screen->queued_drm_lease_devices);
xorg_list_init(&xwl_screen->drm_leases);
xorg_list_init(&xwl_screen->pending_wl_surface_destroy);
xwl_screen->depth = 24;
if (!monitorResolution)
@ -662,6 +764,10 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
fbPictureInit(pScreen, 0, 0);
#ifdef MITSHM
ShmRegisterFbFuncs(pScreen);
#endif
#ifdef HAVE_XSHMFENCE
if (!miSyncShmScreenInit(pScreen))
return FALSE;
@ -736,6 +842,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
return FALSE;
AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen);
AddCallback(&RootWindowFinalizeCallback, xwl_root_window_finalized_callback, pScreen);
xwl_screen_setup_custom_vector(xwl_screen);
xwl_screen_roundtrip(xwl_screen);

View File

@ -36,6 +36,7 @@
#include "xwayland-types.h"
#include "xwayland-output.h"
#include "xwayland-glamor.h"
#include "xwayland-drm-lease.h"
struct xwl_format {
uint32_t format;
@ -67,6 +68,9 @@ struct xwl_screen {
ResizeWindowProcPtr ResizeWindow;
MoveWindowProcPtr MoveWindow;
int (*GrabServer) (ClientPtr client);
int (*UngrabServer) (ClientPtr client);
struct xorg_list output_list;
struct xorg_list seat_list;
struct xorg_list damage_window_list;
@ -82,9 +86,15 @@ struct xwl_screen {
struct xdg_wm_base *xdg_wm_base;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints;
struct zwp_pointer_gestures_v1 *pointer_gestures;
struct zwp_xwayland_keyboard_grab_manager_v1 *wp_grab;
struct zwp_linux_dmabuf_v1 *dmabuf;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wp_viewporter *viewporter;
struct xorg_list drm_lease_devices;
struct xorg_list queued_drm_lease_devices;
struct xorg_list drm_leases;
struct xorg_list pending_wl_surface_destroy;
uint32_t serial;
#define XWL_FORMAT_ARGB8888 (1 << 0)
@ -106,6 +116,9 @@ struct xwl_screen {
struct glamor_context *glamor_ctx;
Atom allow_commits_prop;
/* The preferred GLVND vendor. If NULL, "mesa" is assumed. */
const char *glvnd_vendor;
};
/* Apps which use randr/vidmode to change the mode when going fullscreen,

View File

@ -234,6 +234,15 @@ xwl_shm_create_pixmap(ScreenPtr screen,
(width == 0 && height == 0) || depth < 15)
return fbCreatePixmap(screen, width, height, depth, hint);
stride = PixmapBytePad(width, depth);
size = stride * height;
/* Size in the protocol is an integer, make sure we don't exceed
* INT32_MAX or else the Wayland compositor will raise an error and
* kill the Wayland connection!
*/
if (size > INT32_MAX)
return NULL;
pixmap = fbCreatePixmap(screen, 0, 0, depth, hint);
if (!pixmap)
return NULL;
@ -242,8 +251,6 @@ xwl_shm_create_pixmap(ScreenPtr screen,
if (xwl_pixmap == NULL)
goto err_destroy_pixmap;
stride = PixmapBytePad(width, depth);
size = stride * height;
xwl_pixmap->buffer = NULL;
xwl_pixmap->size = size;
fd = os_create_anonymous_file(size);

View File

@ -30,5 +30,6 @@ struct xwl_pixmap;
struct xwl_window;
struct xwl_screen;
struct xwl_egl_backend;
struct xwl_drm_lease;
#endif /* XWAYLAND_TYPES_H */

View File

@ -46,8 +46,11 @@
#include "viewporter-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */
static DevPrivateKeyRec xwl_window_private_key;
static DevPrivateKeyRec xwl_damage_private_key;
static const char *xwl_surface_tag = "xwl-surface";
static void
xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow,
@ -112,6 +115,24 @@ xwl_window_from_window(WindowPtr window)
return NULL;
}
static void
xwl_window_set_xwayland_tag(struct xwl_window *xwl_window)
{
wl_proxy_set_tag((struct wl_proxy *)xwl_window->surface, &xwl_surface_tag);
}
static void
xwl_window_clear_xwayland_tag(struct xwl_window *xwl_window)
{
wl_proxy_set_tag((struct wl_proxy *)xwl_window->surface, NULL);
}
Bool
is_surface_from_xwl_window(struct wl_surface *surface)
{
return wl_proxy_get_tag((struct wl_proxy *) surface) == &xwl_surface_tag;
}
void
xwl_window_update_property(struct xwl_window *xwl_window,
PropertyStateRec *propstate)
@ -480,6 +501,7 @@ ensure_surface_for_window(WindowPtr window)
send_surface_id_event(xwl_window);
wl_surface_set_user_data(xwl_window->surface, xwl_window);
xwl_window_set_xwayland_tag(xwl_window);
compRedirectWindow(serverClient, window, CompositeRedirectManual);
@ -522,6 +544,7 @@ Bool
xwl_realize_window(WindowPtr window)
{
ScreenPtr screen = window->drawable.pScreen;
CompScreenPtr comp_screen = GetCompScreen(screen);
struct xwl_screen *xwl_screen;
Bool ret;
@ -535,12 +558,20 @@ xwl_realize_window(WindowPtr window)
if (!ret)
return FALSE;
if (xwl_screen->rootless && !window->parent) {
BoxRec box = { 0, 0, xwl_screen->width, xwl_screen->height };
if (xwl_screen->rootless) {
/* We do not want the COW to be mapped when rootless in Xwayland */
if (window == comp_screen->pOverlayWin) {
window->mapped = FALSE;
return TRUE;
}
RegionReset(&window->winSize, &box);
RegionNull(&window->clipList);
RegionNull(&window->borderClip);
if (!window->parent) {
BoxRec box = { 0, 0, xwl_screen->width, xwl_screen->height };
RegionReset(&window->winSize, &box);
RegionNull(&window->clipList);
RegionNull(&window->borderClip);
}
}
if (xwl_screen->rootless ?
@ -554,6 +585,62 @@ xwl_realize_window(WindowPtr window)
return ensure_surface_for_window(window);
}
static void
xwl_surface_destroy_free_timer(struct xwl_wl_surface *xwl_wl_surface)
{
if (xwl_wl_surface->wl_surface_destroy_timer) {
TimerFree(xwl_wl_surface->wl_surface_destroy_timer);
xwl_wl_surface->wl_surface_destroy_timer = NULL;
}
}
void
xwl_window_surface_do_destroy(struct xwl_wl_surface *xwl_wl_surface)
{
wl_surface_destroy(xwl_wl_surface->wl_surface);
xorg_list_del(&xwl_wl_surface->link);
xwl_surface_destroy_free_timer(xwl_wl_surface);
free(xwl_wl_surface);
}
static CARD32
xwl_surface_destroy_callback(OsTimerPtr timer, CARD32 now, void *arg)
{
struct xwl_wl_surface *xwl_wl_surface = arg;
xwl_window_surface_do_destroy(xwl_wl_surface);
return 0;
}
static void
release_wl_surface_for_window(struct xwl_window *xwl_window)
{
struct xwl_wl_surface *xwl_wl_surface;
/* If the Xserver is terminating, destroy the surface immediately */
if ((dispatchException & DE_TERMINATE) == DE_TERMINATE) {
wl_surface_destroy(xwl_window->surface);
return;
}
/* Break the wl_surface / xwl_window relationship */
wl_surface_set_user_data(xwl_window->surface, NULL);
xwl_window_clear_xwayland_tag(xwl_window);
/* Schedule the destruction later, to mitigate the race between X11
* and Wayland processing so that the compositor has the time to
* establish the association before the wl_surface is destroyed.
*/
xwl_wl_surface = xnfcalloc(1, sizeof *xwl_wl_surface);
xwl_wl_surface->wl_surface = xwl_window->surface;
xorg_list_add(&xwl_wl_surface->link,
&xwl_window->xwl_screen->pending_wl_surface_destroy);
xwl_wl_surface->wl_surface_destroy_timer =
TimerSet(NULL, 0, DELAYED_WL_SURFACE_DESTROY,
xwl_surface_destroy_callback, xwl_wl_surface);
}
Bool
xwl_unrealize_window(WindowPtr window)
{
@ -596,16 +683,6 @@ xwl_unrealize_window(WindowPtr window)
if (xwl_window_has_viewport_enabled(xwl_window))
xwl_window_disable_viewport(xwl_window);
wl_surface_destroy(xwl_window->surface);
xorg_list_del(&xwl_window->link_damage);
xorg_list_del(&xwl_window->link_window);
unregister_damage(window);
xwl_window_buffers_dispose(xwl_window);
if (xwl_window->frame_callback)
wl_callback_destroy(xwl_window->frame_callback);
#ifdef GLAMOR_HAS_GBM
if (xwl_screen->present) {
struct xwl_present_window *xwl_present_window, *tmp;
@ -618,6 +695,16 @@ xwl_unrealize_window(WindowPtr window)
}
#endif
release_wl_surface_for_window(xwl_window);
xorg_list_del(&xwl_window->link_damage);
xorg_list_del(&xwl_window->link_window);
unregister_damage(window);
xwl_window_buffers_dispose(xwl_window);
if (xwl_window->frame_callback)
wl_callback_destroy(xwl_window->frame_callback);
free(xwl_window);
dixSetPrivate(&window->devPrivates, &xwl_window_private_key, NULL);
@ -756,6 +843,18 @@ xwl_window_create_frame_callback(struct xwl_window *xwl_window)
xwl_window->frame_callback = wl_surface_frame(xwl_window->surface);
wl_callback_add_listener(xwl_window->frame_callback, &frame_listener,
xwl_window);
#ifdef GLAMOR_HAS_GBM
if (xwl_window->xwl_screen->present) {
struct xwl_present_window *xwl_present_window, *tmp;
xorg_list_for_each_entry_safe(xwl_present_window, tmp,
&xwl_window->frame_callback_list,
frame_callback_list) {
xwl_present_reset_timer(xwl_present_window);
}
}
#endif
}
Bool
@ -805,9 +904,18 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
#endif
buffer = xwl_shm_pixmap_get_wl_buffer(pixmap);
if (!buffer) {
ErrorF("Error getting buffer\n");
return;
}
#ifdef XWL_HAS_GLAMOR
if (xwl_screen->glamor)
xwl_glamor_post_damage(xwl_window, pixmap, region);
if (xwl_screen->glamor) {
if (!xwl_glamor_post_damage(xwl_window, pixmap, region)) {
ErrorF("glamor: Failed to post damage\n");
return;
}
}
#endif
wl_surface_attach(xwl_window->surface, buffer, 0, 0);

View File

@ -37,6 +37,12 @@
#include "xwayland-types.h"
struct xwl_wl_surface {
OsTimerPtr wl_surface_destroy_timer;
struct wl_surface *wl_surface;
struct xorg_list link;
};
struct xwl_window {
struct xwl_screen *xwl_screen;
struct wl_surface *surface;
@ -60,6 +66,8 @@ struct xwl_window {
struct xwl_window *xwl_window_get(WindowPtr window);
struct xwl_window *xwl_window_from_window(WindowPtr window);
Bool is_surface_from_xwl_window(struct wl_surface *surface);
void xwl_window_update_property(struct xwl_window *xwl_window,
PropertyStateRec *propstate);
Bool xwl_window_has_viewport_enabled(struct xwl_window *xwl_window);
@ -81,6 +89,8 @@ void xwl_move_window(WindowPtr window,
Bool xwl_destroy_window(WindowPtr window);
void xwl_window_post_damage(struct xwl_window *xwl_window);
void xwl_window_create_frame_callback(struct xwl_window *xwl_window);
void xwl_window_surface_do_destroy(struct xwl_wl_surface *xwl_wl_surface);
Bool xwl_window_init(void);
#endif /* XWAYLAND_WINDOW_H */

View File

@ -25,7 +25,12 @@
#include <xwayland-config.h>
#if !defined(SYSV) && !defined(WIN32)
#include <sys/resource.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <X11/Xatom.h>
#include <selection.h>
@ -34,6 +39,7 @@
#include <compositeext.h>
#include <compint.h>
#include <glx_extinit.h>
#include <opaque.h>
#include <os.h>
#include <xserver_poll.h>
#include <propertyst.h>
@ -95,6 +101,7 @@ ddxUseMsg(void)
ErrorF("-shm use shared memory for passing buffers\n");
ErrorF("-verbose [n] verbose startup messages\n");
ErrorF("-version show the server version and exit\n");
ErrorF("-noTouchPointerEmulation disable touch pointer emulation\n");
}
static int init_fd = -1;
@ -114,6 +121,33 @@ xwl_show_version(void)
#endif
}
static void
try_raising_nofile_limit(void)
{
#ifdef RLIMIT_NOFILE
struct rlimit rlim;
/* Only fiddle with the limit if not set explicitly from the command line */
if (limitNoFile >= 0)
return;
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
ErrorF("Failed to get the current nofile limit: %s\n", strerror(errno));
return;
}
rlim.rlim_cur = rlim.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
ErrorF("Failed to set the current nofile limit: %s\n", strerror(errno));
return;
}
LogMessageVerb(X_INFO, 3, "Raising the file descriptors limit to %li\n",
rlim.rlim_max);
#endif
}
static void
xwl_add_listen_fd(int argc, char *argv[], int i)
{
@ -185,6 +219,10 @@ ddxProcessArgument(int argc, char *argv[], int i)
xwl_show_version();
exit(0);
}
else if (strcmp(argv[i], "-noTouchPointerEmulation") == 0) {
touchEmulatePointer = FALSE;
return 1;
}
return 0;
}
@ -263,14 +301,13 @@ InitOutput(ScreenInfo * screen_info, int argc, char **argv)
screen_info->bitmapBitOrder = BITMAP_BIT_ORDER;
screen_info->numPixmapFormats = ARRAY_SIZE(depths);
if (serverGeneration == 1)
if (serverGeneration == 1) {
try_raising_nofile_limit();
LoadExtensionList(xwayland_extensions,
ARRAY_SIZE(xwayland_extensions), FALSE);
}
/* Cast away warning from missing printf annotation for
* wl_log_func_t. Wayland 1.5 will have the annotation, so we can
* remove the cast and require that when it's released. */
wl_log_set_handler_client((void *) xwl_log_handler);
wl_log_set_handler_client(xwl_log_handler);
if (AddScreen(xwl_screen_init, argc, argv) == -1) {
FatalError("Couldn't add screen\n");

View File

@ -1,3 +1,6 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
Name: Xwayland
Description: X Server for Wayland
Version: @PACKAGE_VERSION@
@ -7,3 +10,5 @@ have_eglstream=@have_eglstream@
have_initfd=true
have_listenfd=true
have_verbose=true
have_terminate_delay=true
have_no_touch_pointer_emulation=true

View File

@ -1,491 +0,0 @@
/* dix-config.h.in: not at all generated. -*- c -*- */
#ifndef _DIX_CONFIG_H_
#define _DIX_CONFIG_H_
/* Support BigRequests extension */
#undef BIGREQS
/* Builder address */
#undef BUILDERADDR
/* Builder string */
#undef BUILDERSTRING
/* Default font path */
#undef COMPILEDDEFAULTFONTPATH
/* Miscellaneous server configuration files path */
#undef SERVER_MISC_CONFIG_PATH
/* Support Composite Extension */
#undef COMPOSITE
/* Support Damage extension */
#undef DAMAGE
/* Use OsVendorVErrorF */
#undef DDXOSVERRORF
/* Use ddxBeforeReset */
#undef DDXBEFORERESET
/* Build DPMS extension */
#undef DPMSExtension
/* Build DRI3 extension */
#undef DRI3
/* Build GLX extension */
#undef GLXEXT
/* Build GLX DRI loader */
#undef GLX_DRI
/* Path to DRI drivers */
#undef DRI_DRIVER_PATH
/* Support XDM-AUTH*-1 */
#undef HASXDMAUTH
/* Support SHM */
#undef HAS_SHM
/* Has backtrace support */
#undef HAVE_BACKTRACE
/* Has libunwind support */
#undef HAVE_LIBUNWIND
/* Define to 1 if you have the `cbrt' function. */
#undef HAVE_CBRT
/* Define to 1 if you have the declaration of `program_invocation_short_name', and
to 0 if you don't. */
#undef HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
*/
#undef HAVE_DIRENT_H
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Have execinfo.h */
#undef HAVE_EXECINFO_H
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `getdtablesize' function. */
#undef HAVE_GETDTABLESIZE
/* Define to 1 if you have the `getifaddrs' function. */
#undef HAVE_GETIFADDRS
/* Define to 1 if you have the `getpeereid' function. */
#undef HAVE_GETPEEREID
/* Define to 1 if you have the `getpeerucred' function. */
#undef HAVE_GETPEERUCRED
/* Define to 1 if you have the `getprogname' function. */
#undef HAVE_GETPROGNAME
/* Define to 1 if you have the `getzoneid' function. */
#undef HAVE_GETZONEID
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `bsd' library (-lbsd). */
#undef HAVE_LIBBSD
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
/* Define to 1 if you have the <linux/fb.h> header file. */
#undef HAVE_LINUX_FB_H
/* Define to 1 if you have the `memfd_create' function. */
#undef HAVE_MEMFD_CREATE
/* Define to 1 if you have the `mkostemp' function. */
#undef HAVE_MKOSTEMP
/* Define to 1 if you have the `mmap' function. */
#undef HAVE_MMAP
/* Define to 1 if you have the function pthread_setname_np(const char*) */
#undef HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID
/* Define to 1 if you have the function pthread_setname_np(pthread_t, const char*) */
#undef HAVE_PTHREAD_SETNAME_NP_WITH_TID
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
#undef HAVE_NDIR_H
/* Define to 1 if you have the `reallocarray' function. */
#undef HAVE_REALLOCARRAY
/* Define to 1 if you have the `arc4random_buf' function. */
#undef HAVE_ARC4RANDOM_BUF
/* Define to use libc SHA1 functions */
#undef HAVE_SHA1_IN_LIBC
/* Define to use CommonCrypto SHA1 functions */
#undef HAVE_SHA1_IN_COMMONCRYPTO
/* Define to use CryptoAPI SHA1 functions */
#undef HAVE_SHA1_IN_CRYPTOAPI
/* Define to use libmd SHA1 functions */
#undef HAVE_SHA1_IN_LIBMD
/* Define to use libgcrypt SHA1 functions */
#undef HAVE_SHA1_IN_LIBGCRYPT
/* Define to use libnettle SHA1 functions */
#undef HAVE_SHA1_IN_LIBNETTLE
/* Define to use libsha1 for SHA1 */
#undef HAVE_SHA1_IN_LIBSHA1
/* Define to 1 if you have the `shmctl64' function. */
#undef HAVE_SHMCTL64
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strcasecmp' function. */
#undef HAVE_STRCASECMP
/* Define to 1 if you have the `strcasestr' function. */
#undef HAVE_STRCASESTR
/* Define to 1 if you have the `strncasecmp' function. */
#undef HAVE_STRNCASECMP
/* Define to 1 if you have the `strlcat' function. */
#undef HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strndup' function. */
#undef HAVE_STRNDUP
/* Define to 1 if libsystemd-daemon is available */
#undef HAVE_SYSTEMD_DAEMON
/* Define to 1 if SYSV IPC is available */
#undef HAVE_SYSV_IPC
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_DIR_H
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_NDIR_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H
/* Define to 1 if you have the `timingsafe_memcmp' function. */
#undef HAVE_TIMINGSAFE_MEMCMP
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the <fnmatch.h> header file. */
#undef HAVE_FNMATCH_H
/* Have /dev/urandom */
#undef HAVE_URANDOM
/* Define to 1 if you have the `vasprintf' function. */
#undef HAVE_VASPRINTF
/* Support IPv6 for TCP connections */
#undef IPv6
/* Support os-specific local connections */
#undef LOCALCONN
/* Support MIT-SHM Extension */
#undef MITSHM
/* Enable some debugging code */
#undef DEBUG
/* Name of package */
#undef PACKAGE
/* Internal define for Xinerama */
#undef PANORAMIX
/* Support Present extension */
#undef PRESENT
/* Overall prefix */
#undef PROJECTROOT
/* Support RANDR extension */
#undef RANDR
/* Support Record extension */
#undef XRECORD
/* Support RENDER extension */
#undef RENDER
/* Support X resource extension */
#undef RES
/* Support client ID tracking in X resource extension */
#undef CLIENTIDS
/* Support MIT-SCREEN-SAVER extension */
#undef SCREENSAVER
/* Support Secure RPC ("SUN-DES-1") authentication for X11 clients */
#undef SECURE_RPC
/* Support SHAPE extension */
#undef SHAPE
/* Define to 1 on systems derived from System V Release 4 */
#undef SVR4
/* sysconfdir */
#undef SYSCONFDIR
/* Support TCP socket connections */
#undef TCPCONN
/* Support UNIX socket connections */
#undef UNIXCONN
/* Build X string registry */
#undef XREGISTRY
/* Build X-ACE extension */
#undef XACE
/* Build SELinux extension */
#undef XSELINUX
/* Support XCMisc extension */
#undef XCMISC
/* Build Security extension */
#undef XCSECURITY
/* Support Xdmcp */
#undef XDMCP
/* Build XFree86 BigFont extension */
#undef XF86BIGFONT
/* Support XFree86 Video Mode extension */
#undef XF86VIDMODE
/* Support XFixes extension */
#undef XFIXES
/* Support Xinerama extension */
#undef XINERAMA
/* Current Xorg version */
#undef XORG_VERSION_CURRENT
/* Build Xv Extension */
#undef XvExtension
/* Support XSync extension */
#undef XSYNC
/* Support XTest extension */
#undef XTEST
/* Support Xv extension */
#undef XV
/* Support DRI extension */
#undef XF86DRI
/* Build DRI2 extension */
#undef DRI2
/* Build DBE support */
#undef DBE
/* Vendor name */
#undef XVENDORNAME
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Enable GNU and other extensions to the C environment for GLIBC */
#undef _GNU_SOURCE
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Build Rootless code */
#undef ROOTLESS
/* Define to 1 if unsigned long is 64 bits. */
#undef _XSERVER64
/* System is BSD-like */
#undef CSRG_BASED
/* Define to 1 if `struct sockaddr_in' has a `sin_len' member */
#undef BSD44SOCKETS
/* Support D-Bus */
#undef HAVE_DBUS
/* Use libudev for input hotplug */
#undef CONFIG_UDEV
/* Use libudev for kms enumeration */
#undef CONFIG_UDEV_KMS
/* Use udev_monitor_filter_add_match_tag() */
#undef HAVE_UDEV_MONITOR_FILTER_ADD_MATCH_TAG
/* Use udev_enumerate_add_match_tag() */
#undef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
/* Enable D-Bus core */
#undef NEED_DBUS
/* Support HAL for hotplug */
#undef CONFIG_HAL
/* Enable systemd-logind integration */
#undef SYSTEMD_LOGIND 1
/* Have a monotonic clock from clock_gettime() */
#undef MONOTONIC_CLOCK
/* Define to 1 if the DTrace Xserver provider probes should be built in */
#undef XSERVER_DTRACE
/* Define to 1 if typeof works with your compiler. */
#undef HAVE_TYPEOF
/* Define to __typeof__ if your compiler spells it that way. */
#undef typeof
/* Correctly set _XSERVER64 for OSX fat binaries */
#ifdef __APPLE__
#include "dix-config-apple-verbatim.h"
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Defined if needed to expose struct msghdr.msg_control */
#undef _XOPEN_SOURCE
/* Have support for X shared memory fence library (xshmfence) */
#undef HAVE_XSHMFENCE
/* Use XTrans FD passing support */
#undef XTRANS_SEND_FDS
/* Wrap SIGBUS to catch MIT-SHM faults */
#undef BUSFAULT
/* Don't let Xdefs.h define 'pointer' */
#define _XTYPEDEF_POINTER 1
/* Don't let XIproto define 'Pointer' */
#define _XITYPEDEF_POINTER 1
/* Ask fontsproto to make font path element names const */
#define FONT_PATH_ELEMENT_NAME_CONST 1
/* Build GLAMOR */
#undef GLAMOR
/* Build glamor's GBM-based EGL support */
#undef GLAMOR_HAS_GBM
/* Build glamor/gbm has linear support */
#undef GLAMOR_HAS_GBM_LINEAR
/* GBM has modifiers support */
#undef GBM_BO_WITH_MODIFIERS
/* Glamor can use eglQueryDmaBuf* functions */
#undef GLAMOR_HAS_EGL_QUERY_DMABUF
/* Glamor can use EGL_MESA_query_driver functions */
#undef GLAMOR_HAS_EGL_QUERY_DRIVER
/* byte order */
#undef X_BYTE_ORDER
/* Listen on TCP socket */
#undef LISTEN_TCP
/* Listen on Unix socket */
#undef LISTEN_UNIX
/* Listen on local socket */
#undef LISTEN_LOCAL
/* Define if no local socket credentials interface exists */
#undef NO_LOCAL_CLIENT_CRED
/* Have setitimer support */
#undef HAVE_SETITIMER
/* Have posix_fallocate() */
#undef HAVE_POSIX_FALLOCATE
/* Use input thread */
#undef INPUTTHREAD
/* Have poll() */
#undef HAVE_POLL
/* Have epoll_create1() */
#undef HAVE_EPOLL_CREATE1
/* Have <sys/sysmacros.h> header */
#undef HAVE_SYS_SYSMACROS_H
/* Have sigprocmask */
#undef HAVE_SIGPROCMASK
/* Have isastream */
#undef HAVE_ISASTREAM
#endif /* _DIX_CONFIG_H_ */

View File

@ -61,60 +61,76 @@ SOFTWARE.
#define LATER 1
#define NullClient ((ClientPtr) 0)
#define REQUEST(type) \
type *stuff = (type *)client->requestBuffer
#define REQUEST(type) \
type * stuff = (type *)client->requestBuffer;
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
#define REQUEST_SIZE_MATCH(req)\
if ((sizeof(req) >> 2) != client->req_len)\
return(BadLength)
#define REQUEST_SIZE_MATCH(req) \
do { \
if ((sizeof(req) >> 2) != client->req_len) \
return(BadLength); \
} while (0)
#define REQUEST_AT_LEAST_SIZE(req) \
if ((sizeof(req) >> 2) > client->req_len )\
return(BadLength)
#define REQUEST_AT_LEAST_SIZE(req) \
do { \
if ((sizeof(req) >> 2) > client->req_len) \
return(BadLength); \
} while (0)
#define REQUEST_AT_LEAST_EXTRA_SIZE(req, extra) \
if (((sizeof(req) + ((uint64_t) extra)) >> 2) > client->req_len ) \
return(BadLength)
#define REQUEST_AT_LEAST_EXTRA_SIZE(req, extra) \
do { \
if (((sizeof(req) + ((uint64_t) (extra))) >> 2) > client->req_len) \
return(BadLength); \
} while (0)
#define REQUEST_FIXED_SIZE(req, n)\
if (((sizeof(req) >> 2) > client->req_len) || \
(((n) >> 2) >= client->req_len) || \
((((uint64_t) sizeof(req) + (n) + 3) >> 2) != (uint64_t) client->req_len)) \
return(BadLength)
#define REQUEST_FIXED_SIZE(req, n) \
do { \
if ((((sizeof(req)) >> 2) > client->req_len) || \
(((n) >> 2) >= client->req_len) || \
((((uint64_t) sizeof(req) + (n) + 3) >> 2) != (uint64_t) client->req_len)) \
return(BadLength); \
} while (0)
#define LEGAL_NEW_RESOURCE(id,client)\
if (!LegalNewID(id,client)) \
{\
client->errorValue = id;\
return BadIDChoice;\
}
#define LEGAL_NEW_RESOURCE(id,client) \
do { \
if (!LegalNewID((id), (client))) { \
(client)->errorValue = (id); \
return BadIDChoice; \
} \
} while (0)
#define VALIDATE_DRAWABLE_AND_GC(drawID, pDraw, mode)\
{\
int tmprc = dixLookupDrawable(&(pDraw), drawID, client, M_ANY, mode);\
if (tmprc != Success)\
return tmprc;\
tmprc = dixLookupGC(&(pGC), stuff->gc, client, DixUseAccess);\
if (tmprc != Success)\
return tmprc;\
if ((pGC->depth != pDraw->depth) || (pGC->pScreen != pDraw->pScreen))\
return BadMatch;\
}\
if (pGC->serialNumber != pDraw->serialNumber)\
ValidateGC(pDraw, pGC);
#define VALIDATE_DRAWABLE_AND_GC(drawID, pDraw, mode) \
do { \
int tmprc = dixLookupDrawable(&(pDraw), drawID, client, M_ANY, mode); \
if (tmprc != Success) \
return tmprc; \
tmprc = dixLookupGC(&(pGC), stuff->gc, client, DixUseAccess); \
if (tmprc != Success) \
return tmprc; \
if ((pGC->depth != pDraw->depth) || (pGC->pScreen != pDraw->pScreen)) \
return BadMatch; \
if (pGC->serialNumber != pDraw->serialNumber) \
ValidateGC(pDraw, pGC); \
} while (0)
#define WriteReplyToClient(pClient, size, pReply) { \
if ((pClient)->swapped) \
(*ReplySwapVector[((xReq *)(pClient)->requestBuffer)->reqType]) \
(pClient, (int)(size), pReply); \
else WriteToClient(pClient, (int)(size), (pReply)); }
#define WriteReplyToClient(pClient, size, pReply) \
do { \
if ((pClient)->swapped) \
(*ReplySwapVector[((xReq *)(pClient)->requestBuffer)->reqType]) \
(pClient, (int)(size), pReply); \
else \
WriteToClient(pClient, (int)(size), (pReply)); \
} while (0)
#define WriteSwappedDataToClient(pClient, size, pbuf) \
if ((pClient)->swapped) \
(*(pClient)->pSwapReplyFunc)(pClient, (int)(size), pbuf); \
else WriteToClient(pClient, (int)(size), (pbuf));
#define WriteSwappedDataToClient(pClient, size, pbuf) \
do { \
if ((pClient)->swapped) \
(*(pClient)->pSwapReplyFunc)(pClient, (int)(size), pbuf); \
else \
WriteToClient(pClient, (int)(size), (pbuf)); \
} while (0)
typedef struct _TimeStamp *TimeStampPtr;
@ -130,6 +146,8 @@ extern _X_EXPORT ClientPtr clients[MAXCLIENTS];
extern _X_EXPORT ClientPtr serverClient;
extern _X_EXPORT int currentMaxClients;
extern _X_EXPORT char dispatchExceptionAtReset;
extern _X_EXPORT int terminateDelay;
extern _X_EXPORT Bool touchEmulatePointer;
typedef int HWEventQueueType;
typedef HWEventQueueType *HWEventQueuePtr;
@ -421,6 +439,10 @@ DeliverTouchEvents(DeviceIntPtr /* dev */ ,
InternalEvent * /* ev */ ,
XID /* resource */ );
extern Bool
DeliverGestureEventToOwner(DeviceIntPtr dev, GestureInfoPtr gi,
InternalEvent *ev);
extern void
InitializeSprite(DeviceIntPtr /* pDev */ ,
WindowPtr /* pWin */ );
@ -436,7 +458,7 @@ WindowHasNewCursor(WindowPtr /* pWin */ );
extern Bool
CheckDeviceGrabs(DeviceIntPtr /* device */ ,
DeviceEvent * /* event */ ,
InternalEvent * /* event */ ,
WindowPtr /* ancestor */ );
extern void
@ -610,6 +632,13 @@ extern Bool
IsPointerEvent(InternalEvent *event);
extern Bool
IsTouchEvent(InternalEvent *event);
Bool
IsGestureEvent(InternalEvent *event);
Bool
IsGestureBeginEvent(InternalEvent *event);
Bool
IsGestureEndEvent(InternalEvent *event);
extern _X_EXPORT Bool
IsMaster(DeviceIntPtr dev);
extern _X_EXPORT Bool

View File

@ -61,4 +61,5 @@ extern _X_EXPORT Bool DeletePassiveGrabFromList(GrabPtr /* pMinuendGrab */ );
extern Bool GrabIsPointerGrab(GrabPtr grab);
extern Bool GrabIsKeyboardGrab(GrabPtr grab);
extern Bool GrabIsGestureGrab(GrabPtr grab);
#endif /* DIXGRABS_H */

View File

@ -36,4 +36,7 @@ _X_INTERNAL int GetCoreType(enum EventType type);
_X_INTERNAL int GetXIType(enum EventType type);
_X_INTERNAL int GetXI2Type(enum EventType type);
_X_INTERNAL enum EventType GestureTypeToBegin(enum EventType type);
_X_INTERNAL enum EventType GestureTypeToEnd(enum EventType type);
#endif /* _EVENTCONVERT_H_ */

View File

@ -28,6 +28,7 @@ typedef struct _DeviceEvent DeviceEvent;
typedef struct _DeviceChangedEvent DeviceChangedEvent;
typedef struct _TouchOwnershipEvent TouchOwnershipEvent;
typedef struct _BarrierEvent BarrierEvent;
typedef struct _GestureEvent GestureEvent;
#ifdef XFreeXDGA
typedef struct _DGAEvent DGAEvent;

View File

@ -75,6 +75,12 @@ enum EventType {
ET_XQuartz,
ET_BarrierHit,
ET_BarrierLeave,
ET_GesturePinchBegin,
ET_GesturePinchUpdate,
ET_GesturePinchEnd,
ET_GestureSwipeBegin,
ET_GestureSwipeUpdate,
ET_GestureSwipeEnd,
ET_Internal = 0xFF /* First byte */
};
@ -260,6 +266,38 @@ struct _BarrierEvent {
uint32_t flags;
};
struct _GestureEvent {
unsigned char header; /**< Always ET_Internal */
enum EventType type; /**< One of ET_Gesture{Pinch,Swipe}{Begin,Update,End} */
int length; /**< Length in bytes */
Time time; /**< Time in ms */
int deviceid; /**< Device to post this event for */
int sourceid; /**< The physical source device */
uint32_t num_touches; /**< The number of touches in this gesture */
double root_x; /**< Pos relative to root window */
double root_y; /**< Pos relative to root window */
double delta_x;
double delta_y;
double delta_unaccel_x;
double delta_unaccel_y;
double scale; /**< Only on ET_GesturePinch{Begin,Update} */
double delta_angle; /**< Only on ET_GesturePinch{Begin,Update} */
struct {
uint32_t base; /**< XKB base modifiers */
uint32_t latched; /**< XKB latched modifiers */
uint32_t locked; /**< XKB locked modifiers */
uint32_t effective;/**< XKB effective modifiers */
} mods;
struct {
uint8_t base; /**< XKB base group */
uint8_t latched; /**< XKB latched group */
uint8_t locked; /**< XKB locked group */
uint8_t effective;/**< XKB effective group */
} group;
Window root; /**< Root window of the event */
uint32_t flags; /**< Flags to be copied into the generated event */
};
#ifdef XQUARTZ
#define XQUARTZ_EVENT_MAXARGS 5
struct _XQuartzEvent {
@ -294,6 +332,7 @@ union _InternalEvent {
#ifdef XQUARTZ
XQuartzEvent xquartz_event;
#endif
GestureEvent gesture_event;
};
#endif

View File

@ -192,11 +192,12 @@ extern int
GrabMask * /* eventMask */ );
extern int
GrabTouch(ClientPtr /* client */ ,
DeviceIntPtr /* dev */ ,
DeviceIntPtr /* mod_dev */ ,
GrabParameters * /* param */ ,
GrabMask * /* eventMask */ );
GrabTouchOrGesture(ClientPtr /* client */ ,
DeviceIntPtr /* dev */ ,
DeviceIntPtr /* mod_dev */ ,
int /* type */ ,
GrabParameters * /* param */ ,
GrabMask * /* eventMask */ );
extern int
SelectForWindow(DeviceIntPtr /* dev */ ,

View File

@ -105,6 +105,9 @@ SOFTWARE.
#define TOUCH_POINTER_EMULATED (1 << 5) /* touch event may be pointer emulated */
#define TOUCH_END (1 << 6) /* really end this touch now */
/* GetGestureEvent flags */
#define GESTURE_CANCELLED (1 << 0)
/*int constants for pointer acceleration schemes*/
#define PtrAccelNoOp 0
#define PtrAccelPredictable 1
@ -150,7 +153,9 @@ typedef struct _ValuatorClassRec *ValuatorClassPtr;
typedef struct _ClassesRec *ClassesPtr;
typedef struct _SpriteRec *SpritePtr;
typedef struct _TouchClassRec *TouchClassPtr;
typedef struct _GestureClassRec *GestureClassPtr;
typedef struct _TouchPointInfo *TouchPointInfoPtr;
typedef struct _GestureInfo *GestureInfoPtr;
typedef struct _DDXTouchPointInfo *DDXTouchPointInfoPtr;
typedef union _GrabMask GrabMask;
@ -337,6 +342,9 @@ extern _X_EXPORT Bool InitTouchClassDeviceStruct(DeviceIntPtr /*device */ ,
unsigned int /*mode */ ,
unsigned int /*numAxes */ );
extern _X_EXPORT Bool InitGestureClassDeviceStruct(DeviceIntPtr device,
unsigned int max_touches);
typedef void (*BellProcPtr) (int percent,
DeviceIntPtr device,
void *ctrl,
@ -488,6 +496,33 @@ void QueueTouchEvents(DeviceIntPtr device,
uint32_t ddx_touchid,
int flags, const ValuatorMask *mask);
void InitGestureEvent(InternalEvent *ievent, DeviceIntPtr dev, CARD32 ms,
int type, uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x, double delta_unaccel_y,
double scale, double delta_angle);
int GetGestureEvents(InternalEvent *events, DeviceIntPtr dev,
uint16_t type, uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x,
double delta_unaccel_y,
double scale, double delta_angle);
void QueueGesturePinchEvents(DeviceIntPtr dev, uint16_t type,
uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x,
double delta_unaccel_y,
double scale, double delta_angle);
void QueueGestureSwipeEvents(DeviceIntPtr dev, uint16_t type,
uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x,
double delta_unaccel_y);
extern int GetTouchOwnershipEvents(InternalEvent *events,
DeviceIntPtr pDev,
TouchPointInfoPtr ti,
@ -573,6 +608,12 @@ enum TouchListenerType {
TOUCH_LISTENER_POINTER_REGULAR,
};
enum GestureListenerType {
GESTURE_LISTENER_GRAB,
GESTURE_LISTENER_NONGESTURE_GRAB,
GESTURE_LISTENER_REGULAR
};
extern void TouchInitDDXTouchPoint(DeviceIntPtr dev,
DDXTouchPointInfoPtr ddxtouch);
extern DDXTouchPointInfoPtr TouchBeginDDXTouch(DeviceIntPtr dev,
@ -618,7 +659,24 @@ extern void TouchEndPhysicallyActiveTouches(DeviceIntPtr dev);
extern void TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource);
extern void TouchAcceptAndEnd(DeviceIntPtr dev, int touchid);
extern Bool GestureInitGestureInfo(GestureInfoPtr gesture);
extern GestureInfoPtr GestureBeginGesture(DeviceIntPtr dev, InternalEvent *ev);
extern GestureInfoPtr GestureFindActiveByEventType(DeviceIntPtr dev, int type);
extern void GestureEndGesture(GestureInfoPtr gi);
extern Bool GestureResourceIsOwner(GestureInfoPtr gi, XID resource);
extern void GestureAddListener(GestureInfoPtr gi, XID resource, int resource_type,
enum GestureListenerType type,
WindowPtr window, GrabPtr grab);
extern void GestureSetupListener(DeviceIntPtr dev, GestureInfoPtr gi,
InternalEvent *ev);
extern Bool GestureBuildSprite(DeviceIntPtr sourcedev, GestureInfoPtr gi);
extern void GestureListenerGone(XID resource);
extern void GestureEndActiveGestures(DeviceIntPtr dev);
extern void GestureEmitGestureEndToOwner(DeviceIntPtr dev, GestureInfoPtr gi);
extern void ProcessGestureEvent(InternalEvent *ev, DeviceIntPtr dev);
/* misc event helpers */
extern void CopyPartialInternalEvent(InternalEvent* dst_event, const InternalEvent* src_event);
extern Mask GetEventMask(DeviceIntPtr dev, xEvent *ev, InputClientsPtr clients);
extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event);
extern Bool WindowXI2MaskIsset(DeviceIntPtr dev, WindowPtr win, xEvent *ev);

View File

@ -75,7 +75,7 @@ extern _X_EXPORT int CountBits(const uint8_t * mask, int len);
* events to the protocol, the server will not support these events until
* this number here is bumped.
*/
#define XI2LASTEVENT XI_BarrierLeave
#define XI2LASTEVENT XI_GestureSwipeEnd
#define XI2MASKSIZE ((XI2LASTEVENT >> 3) + 1) /* no of bytes for masks */
/**
@ -352,6 +352,32 @@ typedef struct _TouchClassRec {
Mask motionMask;
} TouchClassRec;
typedef struct _GestureListener {
XID listener; /* grabs/event selection IDs receiving
* events for this gesture */
int resource_type; /* listener's resource type */
enum GestureListenerType type;
WindowPtr window;
GrabPtr grab;
} GestureListener;
typedef struct _GestureInfo {
int sourceid; /* Source device's ID for this gesture */
Bool active; /* whether or not the gesture is active */
uint8_t type; /* Gesture type: either ET_GesturePinchBegin or
ET_GestureSwipeBegin. Valid if active == TRUE */
int num_touches; /* The number of touches in the gesture */
SpriteRec sprite; /* window trace for delivery */
GestureListener listener; /* the listener that will receive events */
Bool has_listener; /* true if listener has been setup already */
} GestureInfoRec;
typedef struct _GestureClassRec {
int sourceid;
GestureInfoRec gesture;
unsigned short max_touches; /* maximum number of touches, may be 0 */
} GestureClassRec;
typedef struct _ButtonClassRec {
int sourceid;
CARD8 numButtons;
@ -435,6 +461,7 @@ typedef struct _ClassesRec {
KeyClassPtr key;
ValuatorClassPtr valuator;
TouchClassPtr touch;
GestureClassPtr gesture;
ButtonClassPtr button;
FocusClassPtr focus;
ProximityClassPtr proximity;
@ -550,6 +577,7 @@ typedef struct _DeviceIntRec {
KeyClassPtr key;
ValuatorClassPtr valuator;
TouchClassPtr touch;
GestureClassPtr gesture;
ButtonClassPtr button;
FocusClassPtr focus;
ProximityClassPtr proximity;

View File

@ -46,9 +46,11 @@ struct _ValuatorMask {
extern void verify_internal_event(const InternalEvent *ev);
extern void init_device_event(DeviceEvent *event, DeviceIntPtr dev, Time ms,
enum DeviceEventSource event_source);
extern void init_gesture_event(GestureEvent *event, DeviceIntPtr dev, Time ms);
extern int event_get_corestate(DeviceIntPtr mouse, DeviceIntPtr kbd);
extern void event_set_state(DeviceIntPtr mouse, DeviceIntPtr kbd,
DeviceEvent *event);
extern void event_set_state_gesture(DeviceIntPtr kbd, GestureEvent *event);
extern Mask event_get_filter_from_type(DeviceIntPtr dev, int evtype);
extern Mask event_get_filter_from_xi2type(int evtype);

View File

@ -2,12 +2,8 @@ version_split = meson.project_version().split('.')
major = version_split[0].to_int()
minor = version_split[1].to_int()
patch = version_split[2].to_int()
if version_split.length() == 4
subpatch = version_split[3].to_int()
else
subpatch = 0
endif
# convert to the old-style 1.x.y version scheme used up to 1.20.x for backwards compatibility
release = 1 * 10000000 + major * 100000 + minor * 1000 + patch
dri_dep = dependency('dri', required: build_glx)
@ -18,8 +14,17 @@ conf_data.set('_DIX_CONFIG_H_', '1')
conf_data.set('HAVE_TYPEOF', cc.compiles('''
int foo(int bar) { typeof(bar) baz = 1; return baz; }
''',
name: 'typeof()'))
name: 'typeof()') ? '1' : false)
# For feature macros we're using either false (boolean) or '1', which correspond to the macro being
# not defined at all and defined to 1. This is to match autotools behavior and thus preserve
# backwards compatibility with all the existing code that uses #ifdef to check if feature is
# enabled. This ifdef would pass if the macro is defined to 0 which would silently break code
# in various places.
#
# As a complication when we read the configuration from conf_data back we get either string or
# bool. Meson does not like comparing things of different types so we always convert the returned
# value to an integer using to_int().
conf_data.set('MONOTONIC_CLOCK', cc.has_function('clock_gettime') and
cc.compiles('''
#define _POSIX_C_SOURCE 200112L
@ -29,9 +34,9 @@ cc.compiles('''
#error CLOCK_MONOTONIC not defined
#endif
''',
name: 'CLOCK_MONOTONIC'))
name: 'CLOCK_MONOTONIC') ? '1' : false)
conf_data.set('XSERVER_DTRACE', with_dtrace)
conf_data.set('XSERVER_DTRACE', with_dtrace ? '1' : false)
if host_machine.endian() == 'little'
conf_data.set('X_BYTE_ORDER', 'X_LITTLE_ENDIAN')
@ -50,7 +55,7 @@ conf_data.set('_GNU_SOURCE', '1')
# autoconf checks for /dev/xf86 here, but the test should be based on
# the target, not the build system. Could we get rid of this and just
# ifdef for openbsd?
conf_data.set('HAS_APERTURE_DRV', host_machine.system() == 'openbsd')
conf_data.set('HAS_APERTURE_DRV', host_machine.system() == 'openbsd' ? '1' : false)
if get_option('input_thread') == 'false'
enable_input_thread = false
@ -64,13 +69,14 @@ else
enable_input_thread = false
endif
endif
conf_data.set('HAVE_INPUTTHREAD', enable_input_thread)
conf_data.set('INPUTTHREAD', enable_input_thread ? '1' : false)
if cc.compiles('''
#define _GNU_SOURCE 1
#include <pthread.h>
void foo(int bar) { pthread_setname_np(pthread_self(), "example"); }
''',
args: '-Werror-implicit-function-declaration',
name: 'pthread_setname_np(tid, name)')
conf_data.set('HAVE_PTHREAD_SETNAME_NP_WITH_TID', 1)
elif cc.compiles('''
@ -78,80 +84,83 @@ elif cc.compiles('''
#include <pthread.h>
void foo(int bar) { pthread_setname_np("example"); }
''',
args: '-Werror-implicit-function-declaration',
name: 'pthread_setname_np(name)')
conf_data.set('HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID', 1)
endif
conf_data.set('HAVE_LIBBSD', libbsd_dep.found())
conf_data.set('HAVE_XSHMFENCE', xshmfence_dep.found())
conf_data.set('WITH_LIBDRM', libdrm_required)
conf_data.set('HAVE_LIBBSD', libbsd_dep.found() ? '1' : false)
conf_data.set('HAVE_XSHMFENCE', xshmfence_dep.found() ? '1' : false)
conf_data.set('WITH_LIBDRM', libdrm_required ? '1' : false)
conf_data.set('GLAMOR_HAS_EGL_QUERY_DMABUF',
epoxy_dep.found() and epoxy_dep.version().version_compare('>= 1.4.4'))
epoxy_dep.found() and epoxy_dep.version().version_compare('>= 1.4.4') ? '1' : false)
conf_data.set('GLAMOR_HAS_EGL_QUERY_DRIVER',
epoxy_dep.found() and epoxy_dep.version().version_compare('>= 1.5.4'))
conf_data.set('GLXEXT', build_glx)
conf_data.set('GLAMOR', build_glamor)
conf_data.set('GLAMOR_HAS_GBM', gbm_dep.found())
epoxy_dep.found() and epoxy_dep.version().version_compare('>= 1.5.4') ? '1' : false)
conf_data.set('GLXEXT', build_glx ? '1' : false)
conf_data.set('GLAMOR', build_glamor ? '1' : false)
conf_data.set('GLAMOR_HAS_GBM', gbm_dep.found() ? '1' : false)
conf_data.set('GLAMOR_HAS_GBM_LINEAR',
build_glamor and gbm_dep.found() and gbm_dep.version().version_compare('>= 10.6'))
build_glamor and gbm_dep.found() and gbm_dep.version().version_compare('>= 10.6') ? '1' : false)
conf_data.set('GBM_BO_WITH_MODIFIERS',
build_glamor and gbm_dep.found() and gbm_dep.version().version_compare('>= 17.1'))
build_glamor and gbm_dep.found() and gbm_dep.version().version_compare('>= 17.1') ? '1' : false)
conf_data.set('GBM_BO_FD_FOR_PLANE',
build_glamor and gbm_dep.found() and gbm_dep.version().version_compare('>= 21.1') ? '1' : false)
conf_data.set_quoted('SERVER_MISC_CONFIG_PATH', serverconfigdir)
conf_data.set_quoted('PROJECTROOT', get_option('prefix'))
conf_data.set_quoted('SYSCONFDIR', join_paths(get_option('prefix'), get_option('sysconfdir')))
conf_data.set_quoted('COMPILEDDEFAULTFONTPATH', default_font_path)
conf_data.set('HASXDMAUTH', has_xdm_auth)
conf_data.set('SECURE_RPC', get_option('secure-rpc'))
conf_data.set('HASXDMAUTH', has_xdm_auth ? '1' : false)
conf_data.set('SECURE_RPC', get_option('secure-rpc') ? '1' : false)
conf_data.set('HAVE_DLFCN_H', cc.has_header('dlfcn.h'))
conf_data.set('HAVE_EXECINFO_H', cc.has_header('execinfo.h'))
conf_data.set('HAVE_FCNTL_H', cc.has_header('fcntl.h'))
conf_data.set('HAVE_FNMATCH_H', cc.has_header('fnmatch.h'))
conf_data.set('HAVE_STDLIB_H', cc.has_header('stdlib.h'))
conf_data.set('HAVE_STRING_H', cc.has_header('string.h'))
conf_data.set('HAVE_STRINGS_H', cc.has_header('strings.h'))
conf_data.set('HAVE_SYS_UTSNAME_H', cc.has_header('sys/utsname.h'))
conf_data.set('HAVE_SYS_SYSMACROS_H', cc.has_header('sys/sysmacros.h'))
conf_data.set('HAVE_UNISTD_H', cc.has_header('unistd.h'))
conf_data.set('HAVE_DLFCN_H', cc.has_header('dlfcn.h') ? '1' : false)
conf_data.set('HAVE_EXECINFO_H', cc.has_header('execinfo.h') ? '1' : false)
conf_data.set('HAVE_FCNTL_H', cc.has_header('fcntl.h') ? '1' : false)
conf_data.set('HAVE_FNMATCH_H', cc.has_header('fnmatch.h') ? '1' : false)
conf_data.set('HAVE_STDLIB_H', cc.has_header('stdlib.h') ? '1' : false)
conf_data.set('HAVE_STRING_H', cc.has_header('string.h') ? '1' : false)
conf_data.set('HAVE_STRINGS_H', cc.has_header('strings.h') ? '1' : false)
conf_data.set('HAVE_SYS_UTSNAME_H', cc.has_header('sys/utsname.h') ? '1' : false)
conf_data.set('HAVE_SYS_SYSMACROS_H', cc.has_header('sys/sysmacros.h') ? '1' : false)
conf_data.set('HAVE_UNISTD_H', cc.has_header('unistd.h') ? '1' : false)
conf_data.set('HAVE_ARC4RANDOM_BUF', cc.has_function('arc4random_buf', dependencies: libbsd_dep))
conf_data.set('HAVE_BACKTRACE', cc.has_function('backtrace'))
conf_data.set('HAVE_CBRT', cc.has_function('cbrt'))
conf_data.set('HAVE_EPOLL_CREATE1', cc.has_function('epoll_create1'))
conf_data.set('HAVE_GETUID', cc.has_function('getuid'))
conf_data.set('HAVE_GETEUID', cc.has_function('geteuid'))
conf_data.set('HAVE_ISASTREAM', cc.has_function('isastream'))
conf_data.set('HAVE_ISSETUGID', cc.has_function('issetugid'))
conf_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
conf_data.set('HAVE_GETPEEREID', cc.has_function('getpeereid'))
conf_data.set('HAVE_GETPEERUCRED', cc.has_function('getpeerucred'))
conf_data.set('HAVE_GETPROGNAME', cc.has_function('getprogname'))
conf_data.set('HAVE_GETZONEID', cc.has_function('getzoneid'))
conf_data.set('HAVE_MEMFD_CREATE', cc.has_function('memfd_create'))
conf_data.set('HAVE_MKOSTEMP', cc.has_function('mkostemp'))
conf_data.set('HAVE_MMAP', cc.has_function('mmap'))
conf_data.set('HAVE_POLL', cc.has_function('poll'))
conf_data.set('HAVE_POLLSET_CREATE', cc.has_function('pollset_create'))
conf_data.set('HAVE_POSIX_FALLOCATE', cc.has_function('posix_fallocate'))
conf_data.set('HAVE_PORT_CREATE', cc.has_function('port_create'))
conf_data.set('HAVE_REALLOCARRAY', cc.has_function('reallocarray', dependencies: libbsd_dep))
conf_data.set('HAVE_SETEUID', cc.has_function('seteuid'))
conf_data.set('HAVE_SETITIMER', cc.has_function('setitimer'))
conf_data.set('HAVE_SHMCTL64', cc.has_function('shmctl64'))
conf_data.set('HAVE_SIGACTION', cc.has_function('sigaction'))
conf_data.set('HAVE_SIGPROCMASK', cc.has_function('sigprocmask'))
conf_data.set('HAVE_STRCASECMP', cc.has_function('strcasecmp'))
conf_data.set('HAVE_STRCASESTR', cc.has_function('strcasestr'))
conf_data.set('HAVE_STRLCAT', cc.has_function('strlcat', dependencies: libbsd_dep))
conf_data.set('HAVE_STRLCPY', cc.has_function('strlcpy', dependencies: libbsd_dep))
conf_data.set('HAVE_STRNCASECMP', cc.has_function('strncasecmp'))
conf_data.set('HAVE_STRNDUP', cc.has_function('strndup') and cc.has_header_symbol('string.h', 'strndup'))
conf_data.set('HAVE_TIMINGSAFE_MEMCMP', cc.has_function('timingsafe_memcmp'))
conf_data.set('HAVE_VASPRINTF', cc.has_function('vasprintf'))
conf_data.set('HAVE_VSNPRINTF', cc.has_function('vsnprintf'))
conf_data.set('HAVE_WALKCONTEXT', cc.has_function('walkcontext'))
conf_data.set('HAVE_ARC4RANDOM_BUF', cc.has_function('arc4random_buf', dependencies: libbsd_dep) ? '1' : false)
conf_data.set('HAVE_BACKTRACE', cc.has_function('backtrace') ? '1' : false)
conf_data.set('HAVE_CBRT', cc.has_function('cbrt') ? '1' : false)
conf_data.set('HAVE_EPOLL_CREATE1', cc.has_function('epoll_create1') ? '1' : false)
conf_data.set('HAVE_GETUID', cc.has_function('getuid') ? '1' : false)
conf_data.set('HAVE_GETEUID', cc.has_function('geteuid') ? '1' : false)
conf_data.set('HAVE_ISASTREAM', cc.has_function('isastream') ? '1' : false)
conf_data.set('HAVE_ISSETUGID', cc.has_function('issetugid') ? '1' : false)
conf_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs') ? '1' : false)
conf_data.set('HAVE_GETPEEREID', cc.has_function('getpeereid') ? '1' : false)
conf_data.set('HAVE_GETPEERUCRED', cc.has_function('getpeerucred') ? '1' : false)
conf_data.set('HAVE_GETPROGNAME', cc.has_function('getprogname') ? '1' : false)
conf_data.set('HAVE_GETZONEID', cc.has_function('getzoneid') ? '1' : false)
conf_data.set('HAVE_MEMFD_CREATE', cc.has_function('memfd_create') ? '1' : false)
conf_data.set('HAVE_MKOSTEMP', cc.has_function('mkostemp') ? '1' : false)
conf_data.set('HAVE_MMAP', cc.has_function('mmap') ? '1' : false)
conf_data.set('HAVE_POLL', cc.has_function('poll') ? '1' : false)
conf_data.set('HAVE_POLLSET_CREATE', cc.has_function('pollset_create') ? '1' : false)
conf_data.set('HAVE_POSIX_FALLOCATE', cc.has_function('posix_fallocate') ? '1' : false)
conf_data.set('HAVE_PORT_CREATE', cc.has_function('port_create') ? '1' : false)
conf_data.set('HAVE_REALLOCARRAY', cc.has_function('reallocarray', dependencies: libbsd_dep) ? '1' : false)
conf_data.set('HAVE_SETEUID', cc.has_function('seteuid') ? '1' : false)
conf_data.set('HAVE_SETITIMER', cc.has_function('setitimer') ? '1' : false)
conf_data.set('HAVE_SHMCTL64', cc.has_function('shmctl64') ? '1' : false)
conf_data.set('HAVE_SIGACTION', cc.has_function('sigaction') ? '1' : false)
conf_data.set('HAVE_SIGPROCMASK', cc.has_function('sigprocmask') ? '1' : false)
conf_data.set('HAVE_STRCASECMP', cc.has_function('strcasecmp') ? '1' : false)
conf_data.set('HAVE_STRCASESTR', cc.has_function('strcasestr') ? '1' : false)
conf_data.set('HAVE_STRLCAT', cc.has_function('strlcat', dependencies: libbsd_dep) ? '1' : false)
conf_data.set('HAVE_STRLCPY', cc.has_function('strlcpy', dependencies: libbsd_dep) ? '1' : false)
conf_data.set('HAVE_STRNCASECMP', cc.has_function('strncasecmp') ? '1' : false)
conf_data.set('HAVE_STRNDUP', cc.has_function('strndup') and cc.has_header_symbol('string.h', 'strndup') ? '1' : false)
conf_data.set('HAVE_TIMINGSAFE_MEMCMP', cc.has_function('timingsafe_memcmp') ? '1' : false)
conf_data.set('HAVE_VASPRINTF', cc.has_function('vasprintf') ? '1' : false)
conf_data.set('HAVE_VSNPRINTF', cc.has_function('vsnprintf') ? '1' : false)
conf_data.set('HAVE_WALKCONTEXT', cc.has_function('walkcontext') ? '1' : false)
conf_data.set('BUSFAULT', conf_data.get('HAVE_SIGACTION'))
@ -167,55 +176,55 @@ if cc.has_header_symbol('sys/socket.h', 'SCM_RIGHTS')
conf_data.set('XTRANS_SEND_FDS', '1')
endif
if not conf_data.get('HAVE_GETPEEREID') and not conf_data.get('HAVE_GETPEERUCRED')
if conf_data.get('HAVE_GETPEEREID').to_int() == 0 and conf_data.get('HAVE_GETPEERUCRED').to_int() == 0
if not cc.has_header_symbol('sys/socket.h', 'SO_PEERCRED')
conf_data.set('NO_LOCAL_CLIENT_CRED', 1)
endif
endif
conf_data.set('TCPCONN', '1')
conf_data.set('UNIXCONN', host_machine.system() != 'windows')
conf_data.set('IPv6', build_ipv6)
conf_data.set('UNIXCONN', host_machine.system() != 'windows' ? '1' : false)
conf_data.set('IPv6', build_ipv6 ? '1' : false)
conf_data.set('BIGREQS', '1')
conf_data.set('COMPOSITE', '1')
conf_data.set('DAMAGE', '1')
conf_data.set('DBE', '1')
conf_data.set('DPMSExtension', build_dpms)
conf_data.set('DRI3', build_dri3)
conf_data.set('DPMSExtension', build_dpms ? '1' : false)
conf_data.set('DRI3', build_dri3 ? '1' : false)
if build_glx
conf_data.set_quoted('DRI_DRIVER_PATH', dri_dep.get_pkgconfig_variable('dridriverdir'))
endif
conf_data.set('HAS_SHM', build_mitshm)
conf_data.set('MITSHM', build_mitshm)
conf_data.set('PANORAMIX', build_xinerama)
conf_data.set('HAS_SHM', build_mitshm ? '1' : false)
conf_data.set('MITSHM', build_mitshm ? '1' : false)
conf_data.set('PANORAMIX', build_xinerama ? '1' : false)
conf_data.set('PRESENT', '1')
conf_data.set('RANDR', '1')
conf_data.set('RES', build_res)
conf_data.set('RES', build_res ? '1' : false)
conf_data.set('RENDER', '1')
conf_data.set('SCREENSAVER', build_screensaver)
conf_data.set('SCREENSAVER', build_screensaver ? '1' : false)
conf_data.set('SHAPE', '1')
conf_data.set('XACE', build_xace)
conf_data.set('XACE', build_xace ? '1' : false)
conf_data.set('XCMISC', '1')
conf_data.set('XCSECURITY', build_xsecurity)
conf_data.set('XDMCP', xdmcp_dep.found())
conf_data.set('XF86BIGFONT', build_xf86bigfont)
conf_data.set('XCSECURITY', build_xsecurity ? '1' : false)
conf_data.set('XDMCP', xdmcp_dep.found() ? '1' : false)
conf_data.set('XF86BIGFONT', build_xf86bigfont ? '1' : false)
conf_data.set('XF86VIDMODE', 1)
conf_data.set('XFIXES', '1')
conf_data.set('XINERAMA', build_xinerama)
conf_data.set('XINERAMA', build_xinerama ? '1' : false)
conf_data.set('XINPUT', '1')
conf_data.set('XRECORD', '1')
conf_data.set('XSELINUX', build_xselinux)
conf_data.set('XSELINUX', build_xselinux ? '1' : false)
conf_data.set('XSYNC', '1')
conf_data.set('XTEST', '1')
conf_data.set('XV', build_xv)
conf_data.set('XvExtension', build_xv)
conf_data.set('XV', build_xv ? '1' : false)
conf_data.set('XvExtension', build_xv ? '1' : false)
conf_data.set('HAVE_SHA1_IN_' + sha1.to_upper(), '1', description: 'Use @0@ SHA1 functions'.format(sha1))
conf_data.set('HAVE_LIBUNWIND', get_option('libunwind'))
enable_debugging = get_option('buildtype') == 'debug'
conf_data.set('DEBUG', enable_debugging)
conf_data.set('DEBUG', enable_debugging ? '1' : false)
conf_data.set_quoted('XVENDORNAME', get_option('vendor_name'))
conf_data.set_quoted('XVENDORNAMESHORT', get_option('vendor_name_short'))
@ -230,7 +239,7 @@ supports_syscons = false
supports_wscons = false
csrg_based = false
if host_machine.system() == 'freebsd' or host_machine.system() == 'dragonflybsd'
if host_machine.system() == 'freebsd' or host_machine.system() == 'dragonfly'
supports_pccons = true
supports_pcvt = true
supports_syscons = true
@ -262,7 +271,7 @@ endif
conf_data.set_quoted('XKB_DFLT_RULES', get_option('xkb_default_rules'))
conf_data.set_quoted('__XSERVERNAME__', 'Xorg')
conf_data.set('CSRG_BASED', csrg_based)
conf_data.set('CSRG_BASED', csrg_based ? '1' : false)
configure_file(output : 'dix-config.h',
configuration : conf_data)
@ -291,8 +300,8 @@ configure_file(output : 'xkb-config.h',
configuration : xkb_data)
xwayland_data = configuration_data()
xwayland_data.set('XWL_HAS_GLAMOR', build_glamor and (gbm_dep.found() or build_eglstream))
xwayland_data.set('XWL_HAS_EGLSTREAM', build_eglstream)
xwayland_data.set('XWL_HAS_GLAMOR', build_glamor and (gbm_dep.found() or build_eglstream) ? '1' : false)
xwayland_data.set('XWL_HAS_EGLSTREAM', build_eglstream ? '1' : false)
configure_file(output : 'xwayland-config.h',
input : 'xwayland-config.h.meson.in',

View File

@ -15,6 +15,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <X11/Xdefs.h>
#include <X11/Xosdefs.h>
#include <X11/Xfuncproto.h>
#include <assert.h>
#include "misc.h"
/*****************************************************************

View File

@ -72,7 +72,7 @@ extern _X_EXPORT int dixChangeWindowProperty(ClientPtr pClient,
int format,
int mode,
unsigned long len,
void *value,
const void *value,
Bool sendevent);
extern _X_EXPORT int DeleteProperty(ClientPtr /*client */ ,

View File

@ -139,12 +139,12 @@
#define SERVER_XF86VIDMODE_MINOR_VERSION 2
/* Fixes */
#define SERVER_XFIXES_MAJOR_VERSION 5
#define SERVER_XFIXES_MAJOR_VERSION 6
#define SERVER_XFIXES_MINOR_VERSION 0
/* X Input */
#define SERVER_XI_MAJOR_VERSION 2
#define SERVER_XI_MINOR_VERSION 3
#define SERVER_XI_MINOR_VERSION 4
/* XKB */
#define SERVER_XKB_MAJOR_VERSION 1

View File

@ -33,6 +33,7 @@ int systemd_logind_take_fd(int major, int minor, const char *path, Bool *paus);
void systemd_logind_release_fd(int major, int minor, int fd);
int systemd_logind_controls_session(void);
void systemd_logind_vtenter(void);
void systemd_logind_drop_master(void);
#else
#define systemd_logind_init()
#define systemd_logind_fini()
@ -40,6 +41,7 @@ void systemd_logind_vtenter(void);
#define systemd_logind_release_fd(major, minor, fd) close(fd)
#define systemd_logind_controls_session() 0
#define systemd_logind_vtenter()
#define systemd_logind_drop_master()
#endif
#endif

View File

@ -1,16 +0,0 @@
/* version-config.h.in: not generated */
#ifndef VERSION_CONFIG_H
#define VERSION_CONFIG_H
/* Vendor man version */
#undef VENDOR_MAN_VERSION
/* Vendor name */
#undef VENDOR_NAME
/* Vendor release */
#undef VENDOR_RELEASE
#endif /* VERSION_CONFIG_H */

View File

@ -1,13 +0,0 @@
/* xwayland-config.h.in: not at all generated. */
#ifndef _XWAYLAND_CONFIG_H_
#define _XWAYLAND_CONFIG_H_
#include <dix-config.h>
/* Build glamor support for Xwayland */
#undef XWL_HAS_GLAMOR
/* Build eglstream support for Xwayland */
#undef XWL_HAS_EGLSTREAM
#endif /* _XWAYLAND_CONFIG_H_ */

Some files were not shown because too many files have changed in this diff Show More