mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-10-29 05:40:16 -04:00
Compare commits
59 commits
b1923ec0b3
...
8198e0c827
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8198e0c827 | ||
|
|
d81525a235 | ||
|
|
4673ef7e9c | ||
|
|
77730f10a0 | ||
|
|
264da6a92b | ||
|
|
cd0d1543c0 | ||
|
|
90187031e6 | ||
|
|
eecf3f7635 | ||
|
|
adf84614ca | ||
|
|
ba9f9a446f | ||
|
|
53fbc2b0c1 | ||
|
|
fdac631d17 | ||
|
|
6c1da92018 | ||
|
|
ca83185e8a | ||
|
|
4a0c4e2119 | ||
|
|
387adc6a79 | ||
|
|
0de833da29 | ||
|
|
2978fd701a | ||
|
|
5c2f31d8d6 | ||
|
|
ce0ac4f29e | ||
|
|
1bee7aa4a7 | ||
|
|
6281ccbd3d | ||
|
|
ecff0ee10c | ||
|
|
827d0c30ad | ||
|
|
62cd0990e8 | ||
|
|
9b169ff945 | ||
|
|
cc06c3825f | ||
|
|
8cad6f7b82 | ||
|
|
4497232102 | ||
|
|
3214f858e2 | ||
|
|
66fc3f007d | ||
|
|
9dd1b2d7e3 | ||
|
|
d2a3d33063 | ||
|
|
9367c4da76 | ||
|
|
af453f876e | ||
|
|
9ec01ab2dc | ||
|
|
6137c8c213 | ||
|
|
7033e74857 | ||
|
|
dbfa8d784e | ||
|
|
1ab6b693b1 | ||
|
|
afd498b6f5 | ||
|
|
7c2ffb0d71 | ||
|
|
02ad102e2d | ||
|
|
74f322c35a | ||
|
|
00dcf6b323 | ||
|
|
ddd348da7e | ||
|
|
ff8b885523 | ||
|
|
893e4fc46d | ||
|
|
9d5de6062b | ||
|
|
37469d5ced | ||
|
|
bdba21ec92 | ||
|
|
597a6b94f5 | ||
|
|
f246e619d1 | ||
|
|
9cb3d7aa9d | ||
|
|
290c36bc50 | ||
|
|
4273a5edc8 | ||
|
|
10df74c240 | ||
|
|
f67db75ec1 | ||
|
|
38f91fe6ad |
32 changed files with 1602 additions and 296 deletions
|
|
@ -43,7 +43,7 @@ include:
|
|||
# API changes. If you need new features from ci-templates you must bump
|
||||
# this to the current SHA you require from the ci-templates repo, however
|
||||
# be aware that you may need to account for API changes when doing so.
|
||||
ref: b791bd48996e3ced9ca13f1c5ee82be8540b8adb
|
||||
ref: 48c2c583a865bd59be21e8938df247faf460099c
|
||||
file:
|
||||
- '/templates/debian.yml'
|
||||
- '/templates/freebsd.yml'
|
||||
|
|
@ -82,7 +82,7 @@ workflow:
|
|||
FDO_DISTRIBUTION_EXEC: 'pip3 install --break-system-packages meson~=0.57.2'
|
||||
# bump this tag every time you change something which requires rebuilding the
|
||||
# base image
|
||||
FDO_DISTRIBUTION_TAG: "2024-03-28.2"
|
||||
FDO_DISTRIBUTION_TAG: "2025-01-21.1"
|
||||
|
||||
.debian-x86_64:
|
||||
extends:
|
||||
|
|
@ -101,6 +101,7 @@ workflow:
|
|||
- .os-debian
|
||||
variables:
|
||||
BUILD_ARCH: "armv7"
|
||||
FDO_DISTRIBUTION_PLATFORM: "linux/arm/v7"
|
||||
|
||||
|
||||
# Does not inherit .ci-rules as we only want it to run in MR context.
|
||||
|
|
@ -154,7 +155,6 @@ armv7-debian-container_prep:
|
|||
stage: "Base container"
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
FDO_BASE_IMAGE: "arm32v7/debian:$FDO_DISTRIBUTION_VERSION"
|
||||
|
||||
|
||||
# Core build environment.
|
||||
|
|
@ -306,11 +306,11 @@ armv7-release-debian-build:
|
|||
.os-freebsd:
|
||||
variables:
|
||||
BUILD_OS: freebsd
|
||||
FDO_DISTRIBUTION_VERSION: "13.2"
|
||||
FDO_DISTRIBUTION_VERSION: "14.3"
|
||||
FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2'
|
||||
# bump this tag every time you change something which requires rebuilding the
|
||||
# base image
|
||||
FDO_DISTRIBUTION_TAG: "2023-08-02.0"
|
||||
FDO_DISTRIBUTION_TAG: "2025-07-20.0"
|
||||
# Don't build documentation since installing the required tools massively
|
||||
# increases the VM image (and therefore container) size.
|
||||
MESON_ARGS: "--fatal-meson-warnings -Dwerror=true -Ddocumentation=false"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "xcursor.h"
|
||||
#include "wayland-cursor.h"
|
||||
#include "wayland-client.h"
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -68,11 +69,16 @@ shm_pool_create(struct wl_shm *shm, int size)
|
|||
goto err_close;
|
||||
|
||||
pool->pool = wl_shm_create_pool(shm, pool->fd, size);
|
||||
if (!pool->pool)
|
||||
goto err_unmap;
|
||||
|
||||
pool->size = size;
|
||||
pool->used = 0;
|
||||
|
||||
return pool;
|
||||
|
||||
err_unmap:
|
||||
munmap(pool->data, size);
|
||||
err_close:
|
||||
close(pool->fd);
|
||||
err_free:
|
||||
|
|
@ -279,7 +285,8 @@ wl_cursor_create_from_xcursor_images(struct xcursor_images *images,
|
|||
{
|
||||
struct cursor *cursor;
|
||||
struct cursor_image *image;
|
||||
int i, size;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
cursor = malloc(sizeof *cursor);
|
||||
if (!cursor)
|
||||
|
|
@ -309,7 +316,12 @@ wl_cursor_create_from_xcursor_images(struct xcursor_images *images,
|
|||
image->image.hotspot_y = images->images[i]->yhot;
|
||||
image->image.delay = images->images[i]->delay;
|
||||
|
||||
size = image->image.width * image->image.height * 4;
|
||||
size = (size_t) image->image.width * image->image.height * 4;
|
||||
if (size > INT_MAX) {
|
||||
free(image);
|
||||
break;
|
||||
}
|
||||
|
||||
image->offset = shm_pool_allocate(theme->pool, size);
|
||||
if (image->offset < 0) {
|
||||
free(image);
|
||||
|
|
@ -339,6 +351,8 @@ load_callback(struct xcursor_images *images, void *data)
|
|||
{
|
||||
struct wl_cursor_theme *theme = data;
|
||||
struct wl_cursor *cursor;
|
||||
struct wl_cursor **p;
|
||||
size_t s;
|
||||
|
||||
if (wl_cursor_theme_get_cursor(theme, images->name)) {
|
||||
xcursor_images_destroy(images);
|
||||
|
|
@ -348,15 +362,14 @@ load_callback(struct xcursor_images *images, void *data)
|
|||
cursor = wl_cursor_create_from_xcursor_images(images, theme);
|
||||
|
||||
if (cursor) {
|
||||
theme->cursor_count++;
|
||||
theme->cursors =
|
||||
realloc(theme->cursors,
|
||||
theme->cursor_count * sizeof theme->cursors[0]);
|
||||
s = theme->cursor_count + 1;
|
||||
p = realloc(theme->cursors, s * sizeof theme->cursors[0]);
|
||||
|
||||
if (theme->cursors == NULL) {
|
||||
theme->cursor_count--;
|
||||
if (p == NULL) {
|
||||
free(cursor);
|
||||
} else {
|
||||
theme->cursor_count = s;
|
||||
theme->cursors = p;
|
||||
theme->cursors[theme->cursor_count - 1] = cursor;
|
||||
}
|
||||
}
|
||||
|
|
@ -384,6 +397,9 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
|
|||
if (!theme)
|
||||
return NULL;
|
||||
|
||||
if (size < 0 || (size > 0 && INT_MAX / size / 4 < size))
|
||||
goto err;
|
||||
|
||||
if (!name)
|
||||
name = "default";
|
||||
|
||||
|
|
@ -393,7 +409,7 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
|
|||
|
||||
theme->pool = shm_pool_create(shm, size * size * 4);
|
||||
if (!theme->pool)
|
||||
goto out_error_pool;
|
||||
goto err;
|
||||
|
||||
xcursor_load_theme(name, size, load_callback, theme);
|
||||
|
||||
|
|
@ -405,7 +421,7 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
|
|||
|
||||
return theme;
|
||||
|
||||
out_error_pool:
|
||||
err:
|
||||
free(theme);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,6 +259,8 @@ xcursor_read_file_header(FILE *file)
|
|||
return NULL;
|
||||
if (!xcursor_read_uint(file, &head.ntoc))
|
||||
return NULL;
|
||||
if (head.header < XCURSOR_FILE_HEADER_LEN)
|
||||
return NULL;
|
||||
skip = head.header - XCURSOR_FILE_HEADER_LEN;
|
||||
if (skip)
|
||||
if (fseek(file, skip, SEEK_CUR) == EOF)
|
||||
|
|
@ -571,7 +573,7 @@ xcursor_build_theme_dir(const char *dir, const char *theme)
|
|||
* add space for any needed directory separators, one per component,
|
||||
* and one for the trailing null
|
||||
*/
|
||||
full_size = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
|
||||
full_size = (size_t) 1 + homelen + 1 + dirlen + 1 + themelen + 1;
|
||||
full = malloc(full_size);
|
||||
if (!full)
|
||||
return NULL;
|
||||
|
|
@ -686,11 +688,15 @@ load_all_cursors_from_dir(const char *path, int size,
|
|||
void *user_data)
|
||||
{
|
||||
FILE *f;
|
||||
DIR *dir = opendir(path);
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
char *full;
|
||||
struct xcursor_images *images;
|
||||
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
|
|
@ -798,14 +804,14 @@ xcursor_load_theme_protected(const char *theme, int size,
|
|||
free(xcursor_path);
|
||||
}
|
||||
|
||||
/** Load all the cursor of a theme
|
||||
/** Load all the cursors of a theme
|
||||
*
|
||||
* This function loads all the cursor images of a given theme and its
|
||||
* inherited themes. Each cursor is loaded into an struct xcursor_images object
|
||||
* inherited themes. Each cursor is loaded into a struct xcursor_images object
|
||||
* which is passed to the caller's load callback. If a cursor appears
|
||||
* more than once across all the inherited themes, the load callback
|
||||
* will be called multiple times, with possibly different struct xcursor_images
|
||||
* object which have the same name. The user is expected to destroy the
|
||||
* objects which have the same name. The user is expected to destroy the
|
||||
* struct xcursor_images objects passed to the callback with
|
||||
* xcursor_images_destroy().
|
||||
*
|
||||
|
|
|
|||
139
doc/publican/sources/Color.xml
Normal file
139
doc/publican/sources/Color.xml
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<?xml version='1.0' encoding='utf-8' ?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
|
||||
%BOOK_ENTITIES;
|
||||
]>
|
||||
|
||||
<chapter id="chap-Color-Management">
|
||||
<title>Color management</title>
|
||||
|
||||
<section id="sect-Color-Management-preface">
|
||||
<title>Overview</title>
|
||||
|
||||
<para>
|
||||
Color management in Wayland considers only displays. All pictures in
|
||||
Wayland are always display-referred, meaning that the pixel values are
|
||||
intended as-is for some specific display where they would produce the
|
||||
light emissions (<ulink
|
||||
url="https://cie.co.at/eilvterm/17-23-002">stimuli</ulink>) the picture's
|
||||
author desired. Wayland does not support displaying "raw" camera or
|
||||
scanner images as they are not display-referred, nor are they even
|
||||
pictures without complex and subjective processing.
|
||||
</para>
|
||||
<para>
|
||||
Stimuli — the picture itself — are only half of the picture reproduction.
|
||||
The other half is the environment where a display is viewed. A striking
|
||||
example is comparing a brightly lit office to a dark movie theater, the
|
||||
stimuli required to produce a good reading of the picture is greatly
|
||||
different. Therefore display-referred does not include only the display
|
||||
but the viewing environment as well.
|
||||
</para>
|
||||
<para>
|
||||
Window systems have been very well capable of operating without any
|
||||
explicit consideration to color management. This is because there used to
|
||||
be the implicit assumption of the standard display, the sRGB display,
|
||||
which all computer monitors implemented, more or less. The viewing
|
||||
environment was and still is accounted by adjusting the display and/or the
|
||||
room to produce a workable experience. Pictures are authored on a computer
|
||||
system by drawing, painting and adjusting the picture until it looks right
|
||||
on the author's monitor. This implicitly builds the standard display and
|
||||
environment assumption into the picture data. Deviations from the sRGB
|
||||
specification were minor enough that they often did not matter if not in a
|
||||
professional context like the printing industry. Displaying video material
|
||||
required some more attention to the details, because video and television
|
||||
standards differ enough from the sRGB display. What really made explicit
|
||||
color management a hard requirement for entertainment is the coming of
|
||||
wide color gamut (WCG) and high dynamic range (HDR) materials and
|
||||
displays.
|
||||
</para>
|
||||
<para>
|
||||
The color management design in Wayland follows the general Wayland design
|
||||
principles: compositors tell clients what would be the optimal thing to
|
||||
do, clients tell the compositors what kind of pictures they are actually
|
||||
producing, and then compositors display those pictures the best they can.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Color-Management-Protocol">
|
||||
<title>Protocol Interfaces</title>
|
||||
|
||||
<para>
|
||||
Color management interfaces in Wayland and divided into two protocols:
|
||||
<ulink url="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/tree/main/staging/color-management?ref_type=heads">color-management</ulink>
|
||||
and
|
||||
<ulink url="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/tree/main/staging/color-representation?ref_type=heads">color-representation</ulink>.
|
||||
They are designed to work together, but they can also be used
|
||||
independently when the other one is not needed.
|
||||
</para>
|
||||
|
||||
<section id="sect-Color-Management-Protocol-color-management">
|
||||
<title>Color-management</title>
|
||||
|
||||
<para>
|
||||
Color management protocol has two main purposes. First, it puts the
|
||||
responsibility of color management on the compositor. This means that
|
||||
clients do not necessarily need to care about color management at all,
|
||||
and can display just fine by using the traditional standard display
|
||||
assumption even when the actual display is wildly different. Clients
|
||||
can also choose to target some other assumed display and let the
|
||||
compositor handle it, or they can explicitly render for the actual
|
||||
display at hand. Second, when the window system has multiple different
|
||||
monitors, and a wl_surface happens to span more than one monitor, the
|
||||
compositor can display the surface content correctly on all spanned
|
||||
monitors simultaneously, as much as physically possible.
|
||||
</para>
|
||||
<para>
|
||||
Color-management protocol concentrates on colorimetry: when you have a
|
||||
pixel with RGB values, what stimulus do those values represent. The
|
||||
stimulus definition follows the CIE 1931 two-degree observer model. Some
|
||||
core concepts here are color primaries, white point, transfer function,
|
||||
and dynamic range. The viewing environment is represented in an
|
||||
extremely simplified way as the reference white luminance. The
|
||||
connection between pixel RGB values and stimulus plus viewing
|
||||
environment is recorded in an <emphasis>image description</emphasis>
|
||||
object. Clients can create image description objects and tag
|
||||
<code>wl_surface</code>s with them, to indicate what kind of surface
|
||||
content there will be. Clients can also ask what image description the
|
||||
compositor would prefer to have on the <code>wl_surface</code>, and that
|
||||
preference can change over time, e.g. when the <code>wl_surface</code>
|
||||
is moved from one
|
||||
<code>wl_output</code> to another. Following the compositor's preference
|
||||
may provide advantages in image quality and power consumption.
|
||||
</para>
|
||||
<para>
|
||||
Image description objects can come in two flavors: parametric and
|
||||
ICC-based. The above was written with parametric image descriptions in
|
||||
mind, and they have first-class support for HDR. ICC-based image
|
||||
descriptions are wrapping an ICC profile and have no other data. ICC
|
||||
profiles are the standard tool for standard dynamic range (SDR) display
|
||||
color management. This means the capabilities between the two flavors
|
||||
differ, and one cannot always be replaced by the other. Compositor
|
||||
support for each flavor is optional.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="sect-Color-Management-Protocol-color-representation">
|
||||
<title>Color-representation</title>
|
||||
|
||||
<para>
|
||||
Color-representation protocol deals with (potentially sub-sampled)
|
||||
YCbCr-RGB conversion, quantization range, and the inclusion of alpha in
|
||||
the RGB color channels, a.k.a. pre-multiplication. There are several
|
||||
different specifications on how an YCbCr-like (including ICtCp) signal,
|
||||
with chroma sub-sampling or not, is created from a full-resolution RGB
|
||||
image. Again, a client can tag a <code>wl_surface</code> with
|
||||
color-representation metadata to tell the compositor what kind of pixel
|
||||
data will be displayed through the wl_surface.
|
||||
</para>
|
||||
<para>
|
||||
The main purpose of color-representation is to correctly off-load the
|
||||
YCbCr-RGB conversion to the compositor, which can then opportunistically
|
||||
off-load it further to very power-efficient fixed-function circuitry in
|
||||
a display controller. This can significantly reduce power consumption
|
||||
when watching videos compared to using a GPU for the same, and on some
|
||||
embedded hardware platforms it is a hard requirement for processing high
|
||||
resolution video.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
@ -87,7 +87,7 @@
|
|||
</para>
|
||||
<para>
|
||||
Overall, the philosophy of Wayland is to provide clients with a way to
|
||||
manage windows and how their contents is displayed. Rendering is left
|
||||
manage windows and how their contents are displayed. Rendering is left
|
||||
to clients, and system wide memory management interfaces are used to
|
||||
pass buffer handles between clients and the compositing manager.
|
||||
</para>
|
||||
|
|
|
|||
|
|
@ -97,7 +97,9 @@
|
|||
in the environment). Beginning in Wayland 1.15, implementations can
|
||||
optionally support server socket endpoints located at arbitrary
|
||||
locations in the filesystem by setting <emphasis>WAYLAND_DISPLAY</emphasis>
|
||||
to the absolute path at which the server endpoint listens.
|
||||
to the absolute path at which the server endpoint listens. The socket may
|
||||
also be provided through file descriptor inheritance, in which case
|
||||
<emphasis>WAYLAND_SOCKET</emphasis> is set.
|
||||
</para>
|
||||
<para>
|
||||
Every message is structured as 32-bit words; values are represented in the
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
<xi:include href="Architecture.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Protocol.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Xwayland.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Color.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="ProtocolSpec.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="Client.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="Server.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ publican_sources = [
|
|||
'Protocol.xml',
|
||||
'Xwayland.xml',
|
||||
'Compositors.xml',
|
||||
'Color.xml',
|
||||
'Client.xml',
|
||||
'Server.xml'
|
||||
]
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ if get_option('tests')
|
|||
test(
|
||||
'wayland-egl symbols check',
|
||||
find_program('wayland-egl-symbols-check'),
|
||||
depends: wayland_egl,
|
||||
env: [
|
||||
'WAYLAND_EGL_LIB=@0@'.format(wayland_egl_shared.full_path()),
|
||||
'NM=@0@'.format(nm_path)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
project(
|
||||
'wayland', 'c',
|
||||
version: '1.23.90',
|
||||
version: '1.24.90',
|
||||
license: 'MIT',
|
||||
meson_version: '>= 0.57.0',
|
||||
default_options: [
|
||||
|
|
@ -46,6 +46,7 @@ have_funcs = [
|
|||
'memfd_create',
|
||||
'mremap',
|
||||
'strndup',
|
||||
'gettid',
|
||||
]
|
||||
foreach f: have_funcs
|
||||
config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f))
|
||||
|
|
|
|||
|
|
@ -501,8 +501,10 @@
|
|||
<event name="release">
|
||||
<description summary="compositor releases buffer">
|
||||
Sent when this wl_buffer is no longer used by the compositor.
|
||||
The client is now free to reuse or destroy this buffer and its
|
||||
backing storage.
|
||||
|
||||
For more information on when release events may or may not be sent,
|
||||
and what consequences it has, please see the description of
|
||||
wl_surface.attach.
|
||||
|
||||
If a client receives a release event before the frame callback
|
||||
requested in the same wl_surface.commit that attaches this
|
||||
|
|
@ -1504,7 +1506,8 @@
|
|||
the delivery of wl_buffer.release events becomes undefined. A well
|
||||
behaved client should not rely on wl_buffer.release events in this
|
||||
case. Alternatively, a client could create multiple wl_buffer objects
|
||||
from the same backing storage or use wp_linux_buffer_release.
|
||||
from the same backing storage or use a protocol extension providing
|
||||
per-commit release notifications.
|
||||
|
||||
Destroying the wl_buffer after wl_buffer.release does not change
|
||||
the surface contents. Destroying the wl_buffer before wl_buffer.release
|
||||
|
|
@ -1832,6 +1835,9 @@
|
|||
x and y, combined with the new surface size define in which
|
||||
directions the surface's size changes.
|
||||
|
||||
The exact semantics of wl_surface.offset are role-specific. Refer to
|
||||
the documentation of specific roles for more information.
|
||||
|
||||
Surface location offset is double-buffered state, see
|
||||
wl_surface.commit.
|
||||
|
||||
|
|
@ -1908,9 +1914,10 @@
|
|||
|
||||
<event name="capabilities">
|
||||
<description summary="seat capabilities changed">
|
||||
This is emitted whenever a seat gains or loses the pointer,
|
||||
keyboard or touch capabilities. The argument is a capability
|
||||
enum containing the complete set of capabilities this seat has.
|
||||
This is sent on binding to the seat global or whenever a seat gains
|
||||
or loses the pointer, keyboard or touch capabilities.
|
||||
The argument is a capability enum containing the complete set of
|
||||
capabilities this seat has.
|
||||
|
||||
When the pointer capability is added, a client may create a
|
||||
wl_pointer object using the wl_seat.get_pointer request. This object
|
||||
|
|
@ -1992,9 +1999,9 @@
|
|||
The same seat names are used for all clients. Thus, the name can be
|
||||
shared across processes to refer to a specific wl_seat global.
|
||||
|
||||
The name event is sent after binding to the seat global. This event is
|
||||
only sent once per seat object, and the name does not change over the
|
||||
lifetime of the wl_seat global.
|
||||
The name event is sent after binding to the seat global, and should be sent
|
||||
before announcing capabilities. This event only sent once per seat object,
|
||||
and the name does not change over the lifetime of the wl_seat global.
|
||||
|
||||
Compositors may re-use the same seat name if the wl_seat global is
|
||||
destroyed and re-created later.
|
||||
|
|
@ -3262,4 +3269,31 @@
|
|||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="wl_fixes" version="1">
|
||||
<description summary="wayland protocol fixes">
|
||||
This global fixes problems with other core-protocol interfaces that
|
||||
cannot be fixed in these interfaces themselves.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroys this object"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy_registry">
|
||||
<description summary="destroy a wl_registry">
|
||||
This request destroys a wl_registry object.
|
||||
|
||||
The client should no longer use the wl_registry after making this
|
||||
request.
|
||||
|
||||
The compositor will emit a wl_display.delete_id event with the object ID
|
||||
of the registry and will no longer emit any events on the registry. The
|
||||
client should re-use the object ID once it receives the
|
||||
wl_display.delete_id event.
|
||||
</description>
|
||||
<arg name="registry" type="object" interface="wl_registry"
|
||||
summary="the registry to destroy"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
||||
|
|
|
|||
104
src/connection.c
104
src/connection.c
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -260,7 +262,7 @@ ring_buffer_ensure_space(struct wl_ring_buffer *b, size_t count)
|
|||
* allowed).
|
||||
*/
|
||||
if (net_size > size_pot(size_bits)) {
|
||||
wl_log("Data too big for buffer (%d + %zd > %zd).\n",
|
||||
wl_log("Data too big for buffer (%zu + %zu > %zu).\n",
|
||||
ring_buffer_size(b), count, size_pot(size_bits));
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
|
|
@ -928,7 +930,7 @@ wl_connection_demarshal(struct wl_connection *connection,
|
|||
for (i = 0; i < count; i++) {
|
||||
signature = get_next_argument(signature, &arg);
|
||||
|
||||
if (arg.type != WL_ARG_FD && p + 1 > end) {
|
||||
if (arg.type != WL_ARG_FD && p >= end) {
|
||||
wl_log("message too short, "
|
||||
"object (%d), message %s(%s)\n",
|
||||
closure->sender_id, message->name,
|
||||
|
|
@ -1229,6 +1231,11 @@ wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
|
|||
count + 2, &ffi_type_void, ffi_types);
|
||||
|
||||
implementation = target->implementation;
|
||||
if (!implementation) {
|
||||
wl_abort("Implementation of resource %d of %s is NULL\n",
|
||||
target->id, target->interface->name);
|
||||
}
|
||||
|
||||
if (!implementation[opcode]) {
|
||||
wl_abort("listener function for opcode %u of %s is NULL\n",
|
||||
opcode, target->interface->name);
|
||||
|
|
@ -1351,7 +1358,7 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer,
|
|||
if (arg.type == WL_ARG_FD)
|
||||
continue;
|
||||
|
||||
if (p + 1 > end)
|
||||
if (p >= end)
|
||||
goto overflow;
|
||||
|
||||
switch (arg.type) {
|
||||
|
|
@ -1379,7 +1386,7 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer,
|
|||
size = strlen(closure->args[i].s) + 1;
|
||||
*p++ = size;
|
||||
|
||||
if (p + div_roundup(size, sizeof *p) > end)
|
||||
if (div_roundup(size, sizeof *p) > (uint32_t)(end - p))
|
||||
goto overflow;
|
||||
|
||||
memcpy(p, closure->args[i].s, size);
|
||||
|
|
@ -1394,7 +1401,7 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer,
|
|||
size = closure->args[i].a->size;
|
||||
*p++ = size;
|
||||
|
||||
if (p + div_roundup(size, sizeof *p) > end)
|
||||
if (div_roundup(size, sizeof *p) > (uint32_t)(end - p))
|
||||
goto overflow;
|
||||
|
||||
if (size != 0)
|
||||
|
|
@ -1486,11 +1493,56 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
wl_check_env_token(const char *env, const char *token)
|
||||
{
|
||||
const char *ptr = env;
|
||||
size_t token_len;
|
||||
|
||||
if (env == NULL)
|
||||
return false;
|
||||
|
||||
token_len = strlen(token);
|
||||
|
||||
// Scan the string for comma-separated tokens and look for a match.
|
||||
while (true) {
|
||||
const char *end;
|
||||
size_t len;
|
||||
|
||||
// Skip over any leading separators.
|
||||
while (*ptr == ',')
|
||||
ptr++;
|
||||
|
||||
if (*ptr == '\x00')
|
||||
return false;
|
||||
|
||||
end = strchr(ptr + 1, ',');
|
||||
|
||||
// If there isn't another separarator, then the rest of the string
|
||||
// is one token.
|
||||
if (end == NULL)
|
||||
return (strcmp(ptr, token) == 0);
|
||||
|
||||
len = end - ptr;
|
||||
if (len == token_len && memcmp(ptr, token, len) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip to the next token.
|
||||
ptr += len;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
wl_closure_print(struct wl_closure *closure, struct wl_object *target,
|
||||
int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg),
|
||||
const char *queue_name)
|
||||
const char *queue_name, int color)
|
||||
{
|
||||
#if defined(HAVE_GETTID)
|
||||
static int include_tid = -1;
|
||||
#endif // defined(HAVE_GETTID)
|
||||
int i;
|
||||
struct argument_details arg;
|
||||
const char *signature = closure->message->signature;
|
||||
|
|
@ -1506,19 +1558,41 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target,
|
|||
return;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
time = (uint64_t)((tp.tv_sec % 10000L) * 1000000L + tp.tv_nsec / 1000);
|
||||
time = ((tp.tv_sec % 10000LL) * 1000000LL) + (tp.tv_nsec / 1000);
|
||||
fprintf(f, "%s[%7u.%03u] ",
|
||||
color ? WL_DEBUG_COLOR_GREEN : "",
|
||||
(unsigned int)(time / 1000), (unsigned int)(time % 1000));
|
||||
|
||||
/* Time since Unix epoch in milliseconds, mod 10000 seconds */
|
||||
fprintf(f, "[%7u.%03u] ", (unsigned int)(time / 1000), (unsigned int)(time % 1000));
|
||||
#if defined(HAVE_GETTID)
|
||||
if (include_tid < 0) {
|
||||
include_tid = wl_check_env_token(getenv("WAYLAND_DEBUG"), "thread_id");
|
||||
}
|
||||
|
||||
if (queue_name)
|
||||
fprintf(f, "{%s} ", queue_name);
|
||||
if (include_tid) {
|
||||
fprintf(f, "%sTID#%d ",
|
||||
color ? WL_DEBUG_COLOR_CYAN : "",
|
||||
(int) gettid());
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(f, "%s%s%s#%u.%s(",
|
||||
if (queue_name) {
|
||||
fprintf(f, "%s{%s} ",
|
||||
color ? WL_DEBUG_COLOR_YELLOW : "",
|
||||
queue_name);
|
||||
}
|
||||
|
||||
fprintf(f, "%s%s%s%s%s%s%s#%u%s.%s%s(",
|
||||
color ? WL_DEBUG_COLOR_RED : "",
|
||||
discarded ? "discarded " : "",
|
||||
color ? WL_DEBUG_COLOR_RESET : "",
|
||||
send ? " -> " : "",
|
||||
target->interface->name, target->id,
|
||||
closure->message->name);
|
||||
color ? WL_DEBUG_COLOR_BLUE : "",
|
||||
target->interface->name,
|
||||
color ? WL_DEBUG_COLOR_MAGENTA : "",
|
||||
target->id,
|
||||
color ? WL_DEBUG_COLOR_CYAN : "",
|
||||
closure->message->name,
|
||||
color ? WL_DEBUG_COLOR_RESET : "");
|
||||
|
||||
for (i = 0; i < closure->count; i++) {
|
||||
signature = get_next_argument(signature, &arg);
|
||||
|
|
@ -1583,7 +1657,7 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target,
|
|||
}
|
||||
}
|
||||
|
||||
fprintf(f, ")\n");
|
||||
fprintf(f, ")%s\n", color ? WL_DEBUG_COLOR_RESET : "");
|
||||
|
||||
if (fclose(f) == 0) {
|
||||
fprintf(stderr, "%s", buffer);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <sys/signalfd.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <unistd.h>
|
||||
#include "timespec-util.h"
|
||||
#include "wayland-util.h"
|
||||
#include "wayland-private.h"
|
||||
#include "wayland-server-core.h"
|
||||
|
|
@ -973,57 +974,6 @@ wl_event_loop_dispatch_idle(struct wl_event_loop *loop)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
timespec_to_ms(struct timespec value)
|
||||
{
|
||||
return (value.tv_sec * 1000) + (value.tv_nsec / 1000000);
|
||||
}
|
||||
|
||||
static struct timespec
|
||||
ms_to_timespec(int ms)
|
||||
{
|
||||
struct timespec val;
|
||||
val.tv_sec = ms / 1000;
|
||||
val.tv_nsec = (ms % 1000) * 1000000;
|
||||
return val;
|
||||
}
|
||||
|
||||
static struct timespec
|
||||
timespec_normalize(struct timespec value)
|
||||
{
|
||||
struct timespec result = value;
|
||||
|
||||
while (result.tv_nsec >= 1000000000) {
|
||||
result.tv_nsec -= 1000000000;
|
||||
result.tv_sec++;
|
||||
}
|
||||
|
||||
while (result.tv_nsec < 0) {
|
||||
result.tv_nsec += 1000000000;
|
||||
result.tv_sec--;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct timespec
|
||||
timespec_add(struct timespec a, struct timespec b)
|
||||
{
|
||||
struct timespec result;
|
||||
result.tv_sec = a.tv_sec + b.tv_sec;
|
||||
result.tv_nsec = a.tv_nsec + b.tv_nsec;
|
||||
return timespec_normalize(result);
|
||||
}
|
||||
|
||||
static struct timespec
|
||||
timespec_sub(struct timespec a, struct timespec b)
|
||||
{
|
||||
struct timespec result;
|
||||
result.tv_sec = a.tv_sec - b.tv_sec;
|
||||
result.tv_nsec = a.tv_nsec - b.tv_nsec;
|
||||
return timespec_normalize(result);
|
||||
}
|
||||
|
||||
/** Wait for events and dispatch them
|
||||
*
|
||||
* \param loop The event loop whose sources to wait for.
|
||||
|
|
@ -1052,13 +1002,15 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
|
|||
int i, count;
|
||||
bool has_timers = false;
|
||||
bool use_timeout = timeout > 0;
|
||||
struct timespec now, end;
|
||||
struct timespec now;
|
||||
struct timespec deadline = {0};
|
||||
struct timespec result;
|
||||
|
||||
wl_event_loop_dispatch_idle(loop);
|
||||
|
||||
if (use_timeout) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
end = timespec_add(now, ms_to_timespec(timeout));
|
||||
timespec_add_msec(&deadline, &now, timeout);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
|
@ -1070,7 +1022,8 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
|
|||
|
||||
if (use_timeout) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
timeout = timespec_to_ms(timespec_sub(end, now));
|
||||
timespec_sub(&result, &deadline, &now);
|
||||
timeout = timespec_to_msec(&result);
|
||||
if (timeout <= 0) {
|
||||
/* too late */
|
||||
count = 0;
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ if get_option('libraries')
|
|||
description: 'Server side implementation of the Wayland protocol',
|
||||
version: meson.project_version(),
|
||||
filebase: 'wayland-server',
|
||||
libraries: mathlib_dep,
|
||||
variables: [
|
||||
'datarootdir=' + join_paths('${prefix}', get_option('datadir')),
|
||||
'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name())
|
||||
|
|
@ -251,6 +252,7 @@ if get_option('libraries')
|
|||
description: 'Wayland client side library',
|
||||
version: meson.project_version(),
|
||||
filebase: 'wayland-client',
|
||||
libraries: mathlib_dep,
|
||||
variables: [
|
||||
'datarootdir=' + join_paths('${prefix}', get_option('datadir')),
|
||||
'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name())
|
||||
|
|
|
|||
|
|
@ -1383,6 +1383,11 @@ emit_validator(struct interface *interface, struct enumeration *e)
|
|||
{
|
||||
struct entry *entry;
|
||||
|
||||
printf("#ifndef %s_%s_ENUM_IS_VALID\n",
|
||||
interface->uppercase_name, e->uppercase_name);
|
||||
printf("#define %s_%s_ENUM_IS_VALID\n",
|
||||
interface->uppercase_name, e->uppercase_name);
|
||||
|
||||
printf("/**\n"
|
||||
" * @ingroup iface_%s\n"
|
||||
" * Validate a %s %s value.\n"
|
||||
|
|
@ -1420,6 +1425,9 @@ emit_validator(struct interface *interface, struct enumeration *e)
|
|||
" }\n");
|
||||
}
|
||||
printf("}\n");
|
||||
|
||||
printf("#endif /* %s_%s_ENUM_IS_VALID */\n\n",
|
||||
interface->uppercase_name, e->uppercase_name);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1483,11 +1491,11 @@ emit_enumerations(struct interface *interface, bool with_validators)
|
|||
|
||||
}
|
||||
|
||||
if (with_validators)
|
||||
emit_validator(interface, e);
|
||||
|
||||
printf("#endif /* %s_%s_ENUM */\n\n",
|
||||
interface->uppercase_name, e->uppercase_name);
|
||||
|
||||
if (with_validators)
|
||||
emit_validator(interface, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
311
src/timespec-util.h
Normal file
311
src/timespec-util.h
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* Copyright © 2014 - 2015 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef TIMESPEC_UTIL_H
|
||||
#define TIMESPEC_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
/* Subtract timespecs
|
||||
*
|
||||
* \param r[out] result: a - b
|
||||
* \param a[in] operand
|
||||
* \param b[in] operand
|
||||
*/
|
||||
static inline void
|
||||
timespec_sub(struct timespec *r,
|
||||
const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
r->tv_sec = a->tv_sec - b->tv_sec;
|
||||
r->tv_nsec = a->tv_nsec - b->tv_nsec;
|
||||
if (r->tv_nsec < 0) {
|
||||
r->tv_sec--;
|
||||
r->tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a nanosecond value to a timespec
|
||||
*
|
||||
* \param r[out] result: a + b
|
||||
* \param a[in] base operand as timespec
|
||||
* \param b[in] operand in nanoseconds
|
||||
*/
|
||||
static inline void
|
||||
timespec_add_nsec(struct timespec *r, const struct timespec *a, int64_t b)
|
||||
{
|
||||
r->tv_sec = a->tv_sec + (b / NSEC_PER_SEC);
|
||||
r->tv_nsec = a->tv_nsec + (b % NSEC_PER_SEC);
|
||||
|
||||
if (r->tv_nsec >= NSEC_PER_SEC) {
|
||||
r->tv_sec++;
|
||||
r->tv_nsec -= NSEC_PER_SEC;
|
||||
} else if (r->tv_nsec < 0) {
|
||||
r->tv_sec--;
|
||||
r->tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a millisecond value to a timespec
|
||||
*
|
||||
* \param r[out] result: a + b
|
||||
* \param a[in] base operand as timespec
|
||||
* \param b[in] operand in milliseconds
|
||||
*/
|
||||
static inline void
|
||||
timespec_add_msec(struct timespec *r, const struct timespec *a, int64_t b)
|
||||
{
|
||||
timespec_add_nsec(r, a, b * 1000000);
|
||||
}
|
||||
|
||||
/* Convert timespec to nanoseconds
|
||||
*
|
||||
* \param a timespec
|
||||
* \return nanoseconds
|
||||
*/
|
||||
static inline int64_t
|
||||
timespec_to_nsec(const struct timespec *a)
|
||||
{
|
||||
return (int64_t)a->tv_sec * NSEC_PER_SEC + a->tv_nsec;
|
||||
}
|
||||
|
||||
/* Subtract timespecs and return result in nanoseconds
|
||||
*
|
||||
* \param a[in] operand
|
||||
* \param b[in] operand
|
||||
* \return to_nanoseconds(a - b)
|
||||
*/
|
||||
static inline int64_t
|
||||
timespec_sub_to_nsec(const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
struct timespec r;
|
||||
timespec_sub(&r, a, b);
|
||||
return timespec_to_nsec(&r);
|
||||
}
|
||||
|
||||
/* Convert timespec to milliseconds
|
||||
*
|
||||
* \param a timespec
|
||||
* \return milliseconds
|
||||
*
|
||||
* Rounding to integer milliseconds happens always down (floor()).
|
||||
*/
|
||||
static inline int64_t
|
||||
timespec_to_msec(const struct timespec *a)
|
||||
{
|
||||
return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
/* Subtract timespecs and return result in milliseconds
|
||||
*
|
||||
* \param a[in] operand
|
||||
* \param b[in] operand
|
||||
* \return to_milliseconds(a - b)
|
||||
*/
|
||||
static inline int64_t
|
||||
timespec_sub_to_msec(const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
return timespec_sub_to_nsec(a, b) / 1000000;
|
||||
}
|
||||
|
||||
/* Convert timespec to microseconds
|
||||
*
|
||||
* \param a timespec
|
||||
* \return microseconds
|
||||
*
|
||||
* Rounding to integer microseconds happens always down (floor()).
|
||||
*/
|
||||
static inline int64_t
|
||||
timespec_to_usec(const struct timespec *a)
|
||||
{
|
||||
return (int64_t)a->tv_sec * 1000000 + a->tv_nsec / 1000;
|
||||
}
|
||||
|
||||
/* Convert timespec to protocol data
|
||||
*
|
||||
* \param a timespec
|
||||
* \param tv_sec_hi[out] the high bytes of the seconds part
|
||||
* \param tv_sec_lo[out] the low bytes of the seconds part
|
||||
* \param tv_nsec[out] the nanoseconds part
|
||||
*
|
||||
* The input timespec must be normalized (the nanoseconds part should
|
||||
* be less than 1 second) and non-negative.
|
||||
*/
|
||||
static inline void
|
||||
timespec_to_proto(const struct timespec *a, uint32_t *tv_sec_hi,
|
||||
uint32_t *tv_sec_lo, uint32_t *tv_nsec)
|
||||
{
|
||||
assert(a->tv_sec >= 0);
|
||||
assert(a->tv_nsec >= 0 && a->tv_nsec < NSEC_PER_SEC);
|
||||
|
||||
uint64_t sec64 = a->tv_sec;
|
||||
|
||||
*tv_sec_hi = sec64 >> 32;
|
||||
*tv_sec_lo = sec64 & 0xffffffff;
|
||||
*tv_nsec = a->tv_nsec;
|
||||
}
|
||||
|
||||
/* Convert nanoseconds to timespec
|
||||
*
|
||||
* \param a timespec
|
||||
* \param b nanoseconds
|
||||
*/
|
||||
static inline void
|
||||
timespec_from_nsec(struct timespec *a, int64_t b)
|
||||
{
|
||||
a->tv_sec = b / NSEC_PER_SEC;
|
||||
a->tv_nsec = b % NSEC_PER_SEC;
|
||||
}
|
||||
|
||||
/* Convert microseconds to timespec
|
||||
*
|
||||
* \param a timespec
|
||||
* \param b microseconds
|
||||
*/
|
||||
static inline void
|
||||
timespec_from_usec(struct timespec *a, int64_t b)
|
||||
{
|
||||
timespec_from_nsec(a, b * 1000);
|
||||
}
|
||||
|
||||
/* Convert milliseconds to timespec
|
||||
*
|
||||
* \param a timespec
|
||||
* \param b milliseconds
|
||||
*/
|
||||
static inline void
|
||||
timespec_from_msec(struct timespec *a, int64_t b)
|
||||
{
|
||||
timespec_from_nsec(a, b * 1000000);
|
||||
}
|
||||
|
||||
/* Convert protocol data to timespec
|
||||
*
|
||||
* \param a[out] timespec
|
||||
* \param tv_sec_hi the high bytes of seconds part
|
||||
* \param tv_sec_lo the low bytes of seconds part
|
||||
* \param tv_nsec the nanoseconds part
|
||||
*/
|
||||
static inline void
|
||||
timespec_from_proto(struct timespec *a, uint32_t tv_sec_hi,
|
||||
uint32_t tv_sec_lo, uint32_t tv_nsec)
|
||||
{
|
||||
a->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo;
|
||||
a->tv_nsec = tv_nsec;
|
||||
}
|
||||
|
||||
/* Check if a timespec is zero
|
||||
*
|
||||
* \param a timespec
|
||||
* \return whether the timespec is zero
|
||||
*/
|
||||
static inline bool
|
||||
timespec_is_zero(const struct timespec *a)
|
||||
{
|
||||
return a->tv_sec == 0 && a->tv_nsec == 0;
|
||||
}
|
||||
|
||||
/* Check if two timespecs are equal
|
||||
*
|
||||
* \param a[in] timespec to check
|
||||
* \param b[in] timespec to check
|
||||
* \return whether timespecs a and b are equal
|
||||
*/
|
||||
static inline bool
|
||||
timespec_eq(const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
return a->tv_sec == b->tv_sec &&
|
||||
a->tv_nsec == b->tv_nsec;
|
||||
}
|
||||
|
||||
/* Convert milli-Hertz to nanoseconds
|
||||
*
|
||||
* \param mhz frequency in mHz, not zero
|
||||
* \return period in nanoseconds
|
||||
*/
|
||||
static inline int64_t
|
||||
millihz_to_nsec(uint32_t mhz)
|
||||
{
|
||||
assert(mhz > 0);
|
||||
return 1000000000000LL / mhz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a timespec value is after another
|
||||
*
|
||||
* \param a[in] timespec to compare
|
||||
* \param b[in] timespec to compare
|
||||
* \return whether a is after b
|
||||
*/
|
||||
static inline bool
|
||||
timespec_after(const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
return (a->tv_sec == b->tv_sec) ?
|
||||
(a->tv_nsec > b->tv_nsec) :
|
||||
(a->tv_sec > b->tv_sec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add timespecs
|
||||
*
|
||||
* \param r[out] result: a + b
|
||||
* \param a[in] operand
|
||||
* \param b[in] operand
|
||||
*/
|
||||
static inline void
|
||||
timespec_add(struct timespec *r,
|
||||
const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
r->tv_sec = a->tv_sec + b->tv_sec;
|
||||
r->tv_nsec = a->tv_nsec + b->tv_nsec;
|
||||
if (r->tv_nsec > NSEC_PER_SEC) {
|
||||
r->tv_sec++;
|
||||
r->tv_nsec -= NSEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saturating timespec subtraction
|
||||
*
|
||||
* \param r[out] result: max(a - b, 0)
|
||||
* \param a[in] operand
|
||||
* \param b[in] operand
|
||||
*/
|
||||
static inline void
|
||||
timespec_sub_saturate(struct timespec *r,
|
||||
const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
timespec_sub(r, a, b);
|
||||
if (r->tv_sec < 0) {
|
||||
r->tv_sec = 0;
|
||||
r->tv_nsec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* TIMESPEC_UTIL_H */
|
||||
|
|
@ -34,6 +34,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct timespec;
|
||||
|
||||
/** \class wl_proxy
|
||||
*
|
||||
* \brief Represents a protocol object on the client side.
|
||||
|
|
@ -219,6 +221,9 @@ wl_proxy_get_tag(struct wl_proxy *proxy);
|
|||
const char *
|
||||
wl_proxy_get_class(struct wl_proxy *proxy);
|
||||
|
||||
const struct wl_interface *
|
||||
wl_proxy_get_interface(struct wl_proxy *proxy);
|
||||
|
||||
struct wl_display *
|
||||
wl_proxy_get_display(struct wl_proxy *proxy);
|
||||
|
||||
|
|
@ -250,13 +255,29 @@ int
|
|||
wl_display_dispatch_queue(struct wl_display *display,
|
||||
struct wl_event_queue *queue);
|
||||
|
||||
int
|
||||
wl_display_dispatch_timeout(struct wl_display *display,
|
||||
const struct timespec *timeout);
|
||||
|
||||
int
|
||||
wl_display_dispatch_queue_timeout(struct wl_display *display,
|
||||
struct wl_event_queue *queue,
|
||||
const struct timespec *timeout);
|
||||
|
||||
int
|
||||
wl_display_dispatch_queue_pending(struct wl_display *display,
|
||||
struct wl_event_queue *queue);
|
||||
|
||||
int
|
||||
wl_display_dispatch_queue_pending_single(struct wl_display *display,
|
||||
struct wl_event_queue *queue);
|
||||
|
||||
int
|
||||
wl_display_dispatch_pending(struct wl_display *display);
|
||||
|
||||
int
|
||||
wl_display_dispatch_pending_single(struct wl_display *display);
|
||||
|
||||
int
|
||||
wl_display_get_error(struct wl_display *display);
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
#include "wayland-os.h"
|
||||
#include "wayland-client.h"
|
||||
#include "wayland-private.h"
|
||||
#include "timespec-util.h"
|
||||
|
||||
/** \cond */
|
||||
|
||||
|
|
@ -114,6 +115,7 @@ struct wl_display {
|
|||
/** \endcond */
|
||||
|
||||
static int debug_client = 0;
|
||||
static int debug_color = 0;
|
||||
|
||||
/**
|
||||
* This helper function wakes up all threads that are
|
||||
|
|
@ -673,6 +675,9 @@ wl_proxy_add_listener(struct wl_proxy *proxy,
|
|||
* This function is useful in clients with multiple listeners on the same
|
||||
* interface to allow the identification of which code to execute.
|
||||
*
|
||||
* If \ref wl_proxy_add_dispatcher was used, this function returns the
|
||||
* dispatcher_data pointer instead.
|
||||
*
|
||||
* \memberof wl_proxy
|
||||
*/
|
||||
WL_EXPORT const void *
|
||||
|
|
@ -932,7 +937,7 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
|
|||
queue_name = wl_event_queue_get_name(queue);
|
||||
|
||||
wl_closure_print(closure, &proxy->object, true, false, NULL,
|
||||
queue_name);
|
||||
queue_name, debug_color);
|
||||
}
|
||||
|
||||
if (wl_closure_send(closure, proxy->display->connection)) {
|
||||
|
|
@ -1225,10 +1230,23 @@ wl_display_connect_to_fd(int fd)
|
|||
{
|
||||
struct wl_display *display;
|
||||
const char *debug;
|
||||
const char *no_color;
|
||||
const char *force_color;
|
||||
|
||||
no_color = getenv("NO_COLOR");
|
||||
force_color = getenv("FORCE_COLOR");
|
||||
debug = getenv("WAYLAND_DEBUG");
|
||||
if (debug && (strstr(debug, "client") || strstr(debug, "1")))
|
||||
if (debug && (wl_check_env_token(debug, "client") || wl_check_env_token(debug, "1"))) {
|
||||
debug_client = 1;
|
||||
if (isatty(fileno(stderr)))
|
||||
debug_color = 1;
|
||||
}
|
||||
|
||||
if (force_color && force_color[0] != '\0')
|
||||
debug_color = 1;
|
||||
|
||||
if (no_color && no_color[0] != '\0')
|
||||
debug_color = 0;
|
||||
|
||||
display = zalloc(sizeof *display);
|
||||
if (display == NULL) {
|
||||
|
|
@ -1560,6 +1578,28 @@ queue_event(struct wl_display *display, int len)
|
|||
id = p[0];
|
||||
opcode = p[1] & 0xffff;
|
||||
size = p[1] >> 16;
|
||||
|
||||
/*
|
||||
* If the message is larger than the maximum size of the
|
||||
* connection buffer, the connection buffer will fill to
|
||||
* its max size and stay there, with no message ever
|
||||
* successfully being processed. If the user of
|
||||
* libwayland-client uses a level-triggered event loop,
|
||||
* this will cause the client to enter a loop that
|
||||
* consumes CPU. To avoid this, immediately drop the
|
||||
* connection. Since the maximum size of a message should
|
||||
* not depend on the max buffer size chosen by the client,
|
||||
* always compare the message size against the
|
||||
* limit enforced by libwayland 1.22 and below (4096),
|
||||
* rather than the actual value the client chose.
|
||||
*/
|
||||
if (size > WL_MAX_MESSAGE_SIZE) {
|
||||
wl_log("Message length %u exceeds limit %d\n",
|
||||
size, WL_MAX_MESSAGE_SIZE);
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len < size)
|
||||
return 0;
|
||||
|
||||
|
|
@ -1574,12 +1614,16 @@ queue_event(struct wl_display *display, int len)
|
|||
if (debug_client) {
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
|
||||
|
||||
fprintf(stderr, "[%7u.%03u] discarded [%s]#%d.[event %d]"
|
||||
fprintf(stderr, "%s[%7u.%03u] %sdiscarded %s[%s]%s#%u%s.[event %d]%s"
|
||||
"(%d fd, %d byte)\n",
|
||||
debug_color ? WL_DEBUG_COLOR_GREEN : "",
|
||||
time / 1000, time % 1000,
|
||||
debug_color ? WL_DEBUG_COLOR_RED : "",
|
||||
debug_color ? WL_DEBUG_COLOR_BLUE : "",
|
||||
zombie ? "zombie" : "unknown",
|
||||
id, opcode,
|
||||
debug_color ? WL_DEBUG_COLOR_MAGENTA : "", id,
|
||||
debug_color ? WL_DEBUG_COLOR_BLUE : "", opcode,
|
||||
debug_color ? WL_DEBUG_COLOR_RESET : "",
|
||||
num_zombie_fds, size);
|
||||
}
|
||||
if (num_zombie_fds > 0)
|
||||
|
|
@ -1664,7 +1708,7 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
|
|||
!(proxy->dispatcher || proxy->object.implementation);
|
||||
|
||||
wl_closure_print(closure, &proxy->object, false, discarded,
|
||||
id_from_object, queue->name);
|
||||
id_from_object, queue->name, debug_color);
|
||||
}
|
||||
|
||||
if (proxy_destroyed) {
|
||||
|
|
@ -1838,6 +1882,34 @@ err:
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dispatch_queue_single(struct wl_display *display, struct wl_event_queue *queue)
|
||||
{
|
||||
if (display->last_error)
|
||||
goto err;
|
||||
|
||||
while (!wl_list_empty(&display->display_queue.event_list)) {
|
||||
dispatch_event(display, &display->display_queue);
|
||||
if (display->last_error)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!wl_list_empty(&queue->event_list)) {
|
||||
dispatch_event(display, queue);
|
||||
if (display->last_error)
|
||||
goto err;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
err:
|
||||
errno = display->last_error;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Prepare to read events from the display's file descriptor to a queue
|
||||
*
|
||||
* \param display The display context object
|
||||
|
|
@ -1953,20 +2025,142 @@ wl_display_cancel_read(struct wl_display *display)
|
|||
}
|
||||
|
||||
static int
|
||||
wl_display_poll(struct wl_display *display, short int events)
|
||||
wl_display_poll(struct wl_display *display,
|
||||
short int events,
|
||||
const struct timespec *timeout)
|
||||
{
|
||||
int ret;
|
||||
struct pollfd pfd[1];
|
||||
struct timespec now;
|
||||
struct timespec deadline = {0};
|
||||
struct timespec result;
|
||||
struct timespec *remaining_timeout = NULL;
|
||||
|
||||
if (timeout) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
timespec_add(&deadline, &now, timeout);
|
||||
}
|
||||
|
||||
pfd[0].fd = display->fd;
|
||||
pfd[0].events = events;
|
||||
do {
|
||||
ret = poll(pfd, 1, -1);
|
||||
if (timeout) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
timespec_sub_saturate(&result, &deadline, &now);
|
||||
remaining_timeout = &result;
|
||||
}
|
||||
ret = ppoll(pfd, 1, remaining_timeout, NULL);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Dispatch events in an event queue with a timeout
|
||||
*
|
||||
* \param display The display context object
|
||||
* \param queue The event queue to dispatch
|
||||
* \param timeout A timeout describing how long the call should block trying to
|
||||
* dispatch events
|
||||
* \return The number of dispatched events on success, -1 on failure
|
||||
*
|
||||
* This function behaves identical to wl_display_dispatch_queue() except
|
||||
* that it also takes a timeout and returns 0 if the timeout elapsed.
|
||||
*
|
||||
* Passing NULL as a timeout means an infinite timeout. An empty timespec
|
||||
* causes wl_display_dispatch_queue_timeout() to return immediately even if no
|
||||
* events have been dispatched.
|
||||
*
|
||||
* If a timeout is passed to wl_display_dispatch_queue_timeout() it is updated
|
||||
* to the remaining time.
|
||||
*
|
||||
* \sa wl_display_dispatch_queue()
|
||||
*
|
||||
* \memberof wl_display
|
||||
*/
|
||||
WL_EXPORT int
|
||||
wl_display_dispatch_queue_timeout(struct wl_display *display,
|
||||
struct wl_event_queue *queue,
|
||||
const struct timespec *timeout)
|
||||
{
|
||||
int ret;
|
||||
struct timespec now;
|
||||
struct timespec deadline = {0};
|
||||
struct timespec result;
|
||||
struct timespec *remaining_timeout = NULL;
|
||||
|
||||
if (timeout) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
timespec_add(&deadline, &now, timeout);
|
||||
}
|
||||
|
||||
if (wl_display_prepare_read_queue(display, queue) == -1)
|
||||
return wl_display_dispatch_queue_pending(display, queue);
|
||||
|
||||
while (true) {
|
||||
ret = wl_display_flush(display);
|
||||
|
||||
if (ret != -1 || errno != EAGAIN)
|
||||
break;
|
||||
|
||||
if (timeout) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
timespec_sub_saturate(&result, &deadline, &now);
|
||||
remaining_timeout = &result;
|
||||
}
|
||||
ret = wl_display_poll(display, POLLOUT, remaining_timeout);
|
||||
|
||||
if (ret <= 0) {
|
||||
wl_display_cancel_read(display);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't stop if flushing hits an EPIPE; continue so we can read any
|
||||
* protocol error that may have triggered it. */
|
||||
if (ret < 0 && errno != EPIPE) {
|
||||
wl_display_cancel_read(display);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (timeout) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
timespec_sub_saturate(&result, &deadline, &now);
|
||||
remaining_timeout = &result;
|
||||
}
|
||||
|
||||
ret = wl_display_poll(display, POLLIN, remaining_timeout);
|
||||
if (ret <= 0) {
|
||||
wl_display_cancel_read(display);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = wl_display_read_events(display);
|
||||
if (ret == -1)
|
||||
break;
|
||||
|
||||
ret = wl_display_dispatch_queue_pending(display, queue);
|
||||
if (ret != 0)
|
||||
break;
|
||||
|
||||
/* We managed to read data from the display but there is no
|
||||
* complete event to dispatch yet. Try reading again. */
|
||||
if (wl_display_prepare_read_queue(display, queue) == -1)
|
||||
return wl_display_dispatch_queue_pending(display, queue);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
WL_EXPORT int
|
||||
wl_display_dispatch_timeout(struct wl_display *display,
|
||||
const struct timespec *timeout)
|
||||
{
|
||||
return wl_display_dispatch_queue_timeout(display,
|
||||
&display->default_queue,
|
||||
timeout);
|
||||
}
|
||||
|
||||
/** Dispatch events in an event queue
|
||||
*
|
||||
* \param display The display context object
|
||||
|
|
@ -1998,8 +2192,8 @@ wl_display_poll(struct wl_display *display, short int events)
|
|||
* \note Since Wayland 1.5 the display has an extra queue
|
||||
* for its own events (i. e. delete_id). This queue is dispatched always,
|
||||
* no matter what queue we passed as an argument to this function.
|
||||
* That means that this function can return non-0 value even when it
|
||||
* haven't dispatched any event for the given queue.
|
||||
* That means that this function can return even when it has not dispatched any
|
||||
* event for the given queue.
|
||||
*
|
||||
* \sa wl_display_dispatch(), wl_display_dispatch_pending(),
|
||||
* wl_display_dispatch_queue_pending(), wl_display_prepare_read_queue()
|
||||
|
|
@ -2012,37 +2206,10 @@ wl_display_dispatch_queue(struct wl_display *display,
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (wl_display_prepare_read_queue(display, queue) == -1)
|
||||
return wl_display_dispatch_queue_pending(display, queue);
|
||||
ret = wl_display_dispatch_queue_timeout(display, queue, NULL);
|
||||
assert(ret == -1 || ret > 0);
|
||||
|
||||
while (true) {
|
||||
ret = wl_display_flush(display);
|
||||
|
||||
if (ret != -1 || errno != EAGAIN)
|
||||
break;
|
||||
|
||||
if (wl_display_poll(display, POLLOUT) == -1) {
|
||||
wl_display_cancel_read(display);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't stop if flushing hits an EPIPE; continue so we can read any
|
||||
* protocol error that may have triggered it. */
|
||||
if (ret < 0 && errno != EPIPE) {
|
||||
wl_display_cancel_read(display);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wl_display_poll(display, POLLIN) == -1) {
|
||||
wl_display_cancel_read(display);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wl_display_read_events(display) == -1)
|
||||
return -1;
|
||||
|
||||
return wl_display_dispatch_queue_pending(display, queue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Dispatch pending events in an event queue
|
||||
|
|
@ -2073,6 +2240,34 @@ wl_display_dispatch_queue_pending(struct wl_display *display,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/** Dispatch at most one pending event in an event queue
|
||||
*
|
||||
* \param display The display context object
|
||||
* \param queue The event queue to dispatch
|
||||
* \return The number of dispatched events (0 or 1) on success or -1 on failure
|
||||
*
|
||||
* Dispatch at most one pending event for objects assigned to the given
|
||||
* event queue. On failure -1 is returned and errno set appropriately.
|
||||
* If there are no events queued, this function returns immediately.
|
||||
*
|
||||
* \memberof wl_display
|
||||
* \since 1.25.0
|
||||
*/
|
||||
WL_EXPORT int
|
||||
wl_display_dispatch_queue_pending_single(struct wl_display *display,
|
||||
struct wl_event_queue *queue)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pthread_mutex_lock(&display->mutex);
|
||||
|
||||
ret = dispatch_queue_single(display, queue);
|
||||
|
||||
pthread_mutex_unlock(&display->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Process incoming events
|
||||
*
|
||||
* \param display The display context object
|
||||
|
|
@ -2133,6 +2328,25 @@ wl_display_dispatch_pending(struct wl_display *display)
|
|||
&display->default_queue);
|
||||
}
|
||||
|
||||
/** Dispatch at most one pending event in the default event queue.
|
||||
*
|
||||
* \param display The display context object
|
||||
* \return The number of dispatched events (0 or 1) on success or -1 on failure
|
||||
*
|
||||
* Dispatch at most one pending event for objects assigned to the default
|
||||
* event queue. On failure -1 is returned and errno set appropriately.
|
||||
* If there are no events queued, this function returns immediately.
|
||||
*
|
||||
* \memberof wl_display
|
||||
* \since 1.25.0
|
||||
*/
|
||||
WL_EXPORT int
|
||||
wl_display_dispatch_pending_single(struct wl_display *display)
|
||||
{
|
||||
return wl_display_dispatch_queue_pending_single(display,
|
||||
&display->default_queue);
|
||||
}
|
||||
|
||||
/** Retrieve the last error that occurred on a display
|
||||
*
|
||||
* \param display The display context object
|
||||
|
|
@ -2414,6 +2628,20 @@ wl_proxy_get_class(struct wl_proxy *proxy)
|
|||
return proxy->object.interface->name;
|
||||
}
|
||||
|
||||
/** Get the interface of a proxy object
|
||||
*
|
||||
* \param proxy The proxy object
|
||||
* \return The interface of the object associated with the proxy
|
||||
*
|
||||
* \memberof wl_proxy
|
||||
* \since 1.24
|
||||
*/
|
||||
WL_EXPORT const struct wl_interface *
|
||||
wl_proxy_get_interface(struct wl_proxy *proxy)
|
||||
{
|
||||
return proxy->object.interface;
|
||||
}
|
||||
|
||||
/** Get the display of a proxy object
|
||||
*
|
||||
* \param proxy The proxy object
|
||||
|
|
|
|||
|
|
@ -49,6 +49,17 @@
|
|||
#define WL_CLOSURE_MAX_ARGS 20
|
||||
#define WL_BUFFER_DEFAULT_SIZE_POT 12
|
||||
#define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT)
|
||||
#if WL_BUFFER_DEFAULT_MAX_SIZE < WL_MAX_MESSAGE_SIZE
|
||||
# error default buffer cannot hold maximum-sized message
|
||||
#endif
|
||||
|
||||
#define WL_DEBUG_COLOR_RESET "\e[0m"
|
||||
#define WL_DEBUG_COLOR_RED "\e[31m"
|
||||
#define WL_DEBUG_COLOR_GREEN "\e[32m"
|
||||
#define WL_DEBUG_COLOR_YELLOW "\e[33m"
|
||||
#define WL_DEBUG_COLOR_BLUE "\e[34m"
|
||||
#define WL_DEBUG_COLOR_MAGENTA "\e[35m"
|
||||
#define WL_DEBUG_COLOR_CYAN "\e[36m"
|
||||
|
||||
/**
|
||||
* Argument types used in signatures.
|
||||
|
|
@ -226,11 +237,14 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
|
|||
int
|
||||
wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection);
|
||||
|
||||
bool
|
||||
wl_check_env_token(const char *env, const char *token);
|
||||
|
||||
void
|
||||
wl_closure_print(struct wl_closure *closure,
|
||||
struct wl_object *target, int send, int discarded,
|
||||
uint32_t (*n_parse)(union wl_argument *arg),
|
||||
const char *queue_name);
|
||||
const char *queue_name, int color);
|
||||
|
||||
void
|
||||
wl_closure_destroy(struct wl_closure *closure);
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data,
|
|||
uint32_t version, uint32_t id);
|
||||
|
||||
uint32_t
|
||||
wl_display_get_serial(struct wl_display *display);
|
||||
wl_display_get_serial(const struct wl_display *display);
|
||||
|
||||
uint32_t
|
||||
wl_display_next_serial(struct wl_display *display);
|
||||
|
|
@ -324,7 +324,7 @@ void
|
|||
wl_client_flush(struct wl_client *client);
|
||||
|
||||
void
|
||||
wl_client_get_credentials(struct wl_client *client,
|
||||
wl_client_get_credentials(const struct wl_client *client,
|
||||
pid_t *pid, uid_t *uid, gid_t *gid);
|
||||
|
||||
int
|
||||
|
|
@ -586,7 +586,7 @@ void
|
|||
wl_resource_destroy(struct wl_resource *resource);
|
||||
|
||||
uint32_t
|
||||
wl_resource_get_id(struct wl_resource *resource);
|
||||
wl_resource_get_id(const struct wl_resource *resource);
|
||||
|
||||
struct wl_list *
|
||||
wl_resource_get_link(struct wl_resource *resource);
|
||||
|
|
@ -607,7 +607,7 @@ void *
|
|||
wl_resource_get_user_data(struct wl_resource *resource);
|
||||
|
||||
int
|
||||
wl_resource_get_version(struct wl_resource *resource);
|
||||
wl_resource_get_version(const struct wl_resource *resource);
|
||||
|
||||
void
|
||||
wl_resource_set_destructor(struct wl_resource *resource,
|
||||
|
|
@ -617,8 +617,12 @@ int
|
|||
wl_resource_instance_of(struct wl_resource *resource,
|
||||
const struct wl_interface *interface,
|
||||
const void *implementation);
|
||||
|
||||
const char *
|
||||
wl_resource_get_class(struct wl_resource *resource);
|
||||
wl_resource_get_class(const struct wl_resource *resource);
|
||||
|
||||
const struct wl_interface *
|
||||
wl_resource_get_interface(struct wl_resource *resource);
|
||||
|
||||
void
|
||||
wl_resource_add_destroy_listener(struct wl_resource *resource,
|
||||
|
|
@ -654,16 +658,22 @@ void *
|
|||
wl_shm_buffer_get_data(struct wl_shm_buffer *buffer);
|
||||
|
||||
int32_t
|
||||
wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer);
|
||||
wl_shm_buffer_get_stride(const struct wl_shm_buffer *buffer);
|
||||
|
||||
uint32_t
|
||||
wl_shm_buffer_get_format(struct wl_shm_buffer *buffer);
|
||||
wl_shm_buffer_get_format(const struct wl_shm_buffer *buffer);
|
||||
|
||||
int32_t
|
||||
wl_shm_buffer_get_width(struct wl_shm_buffer *buffer);
|
||||
wl_shm_buffer_get_width(const struct wl_shm_buffer *buffer);
|
||||
|
||||
int32_t
|
||||
wl_shm_buffer_get_height(struct wl_shm_buffer *buffer);
|
||||
wl_shm_buffer_get_height(const struct wl_shm_buffer *buffer);
|
||||
|
||||
struct wl_shm_buffer *
|
||||
wl_shm_buffer_ref(struct wl_shm_buffer *buffer);
|
||||
|
||||
void
|
||||
wl_shm_buffer_unref(struct wl_shm_buffer *buffer);
|
||||
|
||||
struct wl_shm_pool *
|
||||
wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer);
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ struct wl_protocol_logger {
|
|||
};
|
||||
|
||||
static int debug_server = 0;
|
||||
static int debug_color = 0;
|
||||
|
||||
static void
|
||||
log_closure(struct wl_resource *resource,
|
||||
|
|
@ -160,7 +161,7 @@ log_closure(struct wl_resource *resource,
|
|||
struct wl_protocol_logger_message message;
|
||||
|
||||
if (debug_server)
|
||||
wl_closure_print(closure, object, send, false, NULL, NULL);
|
||||
wl_closure_print(closure, object, send, false, NULL, NULL, debug_color);
|
||||
|
||||
if (!wl_list_empty(&display->protocol_loggers)) {
|
||||
message.resource = resource;
|
||||
|
|
@ -397,6 +398,29 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
|
|||
wl_connection_copy(connection, p, sizeof p);
|
||||
opcode = p[1] & 0xffff;
|
||||
size = p[1] >> 16;
|
||||
|
||||
/*
|
||||
* If the message is larger than the maximum size of the
|
||||
* connection buffer, the connection buffer will fill to
|
||||
* its max size and stay there, with no message ever
|
||||
* successfully being processed. Since libwayland-server
|
||||
* uses level-triggered epoll, it will cause the server to
|
||||
* enter a loop that consumes CPU. To avoid this,
|
||||
* immediately disconnect the client with a protocol
|
||||
* error. Since the maximum size of a message should not
|
||||
* depend on the buffer size chosen by the compositor,
|
||||
* always compare the message size against the
|
||||
* limit enforced by libwayland 1.22 and below (4096),
|
||||
* rather than the actual value the compositor chose.
|
||||
*/
|
||||
if (size > WL_MAX_MESSAGE_SIZE) {
|
||||
wl_resource_post_error(client->display_resource,
|
||||
WL_DISPLAY_ERROR_INVALID_METHOD,
|
||||
"message length %u exceeds %d",
|
||||
size, WL_MAX_MESSAGE_SIZE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (len < size)
|
||||
break;
|
||||
|
||||
|
|
@ -619,7 +643,7 @@ err_client:
|
|||
* \memberof wl_client
|
||||
*/
|
||||
WL_EXPORT void
|
||||
wl_client_get_credentials(struct wl_client *client,
|
||||
wl_client_get_credentials(const struct wl_client *client,
|
||||
pid_t *pid, uid_t *uid, gid_t *gid)
|
||||
{
|
||||
if (pid)
|
||||
|
|
@ -799,7 +823,7 @@ wl_resource_destroy(struct wl_resource *resource)
|
|||
}
|
||||
|
||||
WL_EXPORT uint32_t
|
||||
wl_resource_get_id(struct wl_resource *resource)
|
||||
wl_resource_get_id(const struct wl_resource *resource)
|
||||
{
|
||||
return resource->object.id;
|
||||
}
|
||||
|
|
@ -853,7 +877,7 @@ wl_resource_get_user_data(struct wl_resource *resource)
|
|||
}
|
||||
|
||||
WL_EXPORT int
|
||||
wl_resource_get_version(struct wl_resource *resource)
|
||||
wl_resource_get_version(const struct wl_resource *resource)
|
||||
{
|
||||
return resource->version;
|
||||
}
|
||||
|
|
@ -900,11 +924,25 @@ wl_resource_get_destroy_listener(struct wl_resource *resource,
|
|||
* \memberof wl_resource
|
||||
*/
|
||||
WL_EXPORT const char *
|
||||
wl_resource_get_class(struct wl_resource *resource)
|
||||
wl_resource_get_class(const struct wl_resource *resource)
|
||||
{
|
||||
return resource->object.interface->name;
|
||||
}
|
||||
|
||||
/** Get the interface of a resource object
|
||||
*
|
||||
* \param resource The resource object
|
||||
* \return The interface of the object associated with the resource
|
||||
*
|
||||
* \memberof wl_resource
|
||||
* \since 1.24
|
||||
*/
|
||||
WL_EXPORT const struct wl_interface *
|
||||
wl_resource_get_interface(struct wl_resource *resource)
|
||||
{
|
||||
return resource->object.interface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener to be called at the beginning of wl_client destruction
|
||||
*
|
||||
|
|
@ -1154,10 +1192,23 @@ wl_display_create(void)
|
|||
{
|
||||
struct wl_display *display;
|
||||
const char *debug;
|
||||
const char *no_color;
|
||||
const char *force_color;
|
||||
|
||||
no_color = getenv("NO_COLOR");
|
||||
force_color = getenv("FORCE_COLOR");
|
||||
debug = getenv("WAYLAND_DEBUG");
|
||||
if (debug && (strstr(debug, "server") || strstr(debug, "1")))
|
||||
if (debug && (wl_check_env_token(debug, "server") || wl_check_env_token(debug, "1"))) {
|
||||
debug_server = 1;
|
||||
if (isatty(fileno(stderr)))
|
||||
debug_color = 1;
|
||||
}
|
||||
|
||||
if (force_color && force_color[0] != '\0')
|
||||
debug_color = 1;
|
||||
|
||||
if (no_color && no_color[0] != '\0')
|
||||
debug_color = 0;
|
||||
|
||||
display = zalloc(sizeof *display);
|
||||
if (display == NULL)
|
||||
|
|
@ -1496,7 +1547,7 @@ wl_global_set_user_data(struct wl_global *global, void *data)
|
|||
* \memberof wl_display
|
||||
*/
|
||||
WL_EXPORT uint32_t
|
||||
wl_display_get_serial(struct wl_display *display)
|
||||
wl_display_get_serial(const struct wl_display *display)
|
||||
{
|
||||
return display->serial;
|
||||
}
|
||||
|
|
@ -1780,6 +1831,24 @@ _wl_display_add_socket(struct wl_display *display, struct wl_socket *s)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Automatically pick a Wayland display socket for the clients to connect to.
|
||||
*
|
||||
* \param display Wayland display to which the socket should be added.
|
||||
* \return The socket name if success. NULL if failed.
|
||||
*
|
||||
* This adds a Unix socket to Wayland display which can be used by clients to
|
||||
* connect to Wayland display. The name of the socket is chosen automatically
|
||||
* as the first available name in the sequence "wayland-0", "wayland-1",
|
||||
* "wayland-2", ..., "wayland-32".
|
||||
*
|
||||
* The string returned by this function is owned by the library and should
|
||||
* not be freed.
|
||||
*
|
||||
* \sa wl_display_add_socket
|
||||
*
|
||||
* \memberof wl_display
|
||||
*/
|
||||
WL_EXPORT const char *
|
||||
wl_display_add_socket_auto(struct wl_display *display)
|
||||
{
|
||||
|
|
@ -2060,7 +2129,7 @@ wl_log_set_handler_server(wl_log_func_t handler)
|
|||
* \param func The function to call to log a new protocol message
|
||||
* \param user_data The user data pointer to pass to \a func
|
||||
*
|
||||
* \return The protol logger object on success, NULL on failure.
|
||||
* \return The protocol logger object on success, NULL on failure.
|
||||
*
|
||||
* \sa wl_protocol_logger_destroy
|
||||
*
|
||||
|
|
|
|||
|
|
@ -84,6 +84,10 @@ struct wl_shm_pool {
|
|||
*/
|
||||
struct wl_shm_buffer {
|
||||
struct wl_resource *resource;
|
||||
int internal_refcount;
|
||||
int external_refcount;
|
||||
struct wl_client *client;
|
||||
struct wl_listener client_destroy_listener;
|
||||
int32_t width, height;
|
||||
int32_t stride;
|
||||
uint32_t format;
|
||||
|
|
@ -143,17 +147,16 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external)
|
|||
{
|
||||
if (external) {
|
||||
pool->external_refcount--;
|
||||
if (!(pool->external_refcount >= 0))
|
||||
if (pool->external_refcount < 0)
|
||||
wl_abort("Requested to unref an external reference to "
|
||||
"pool but none found\n");
|
||||
if (pool->external_refcount == 0)
|
||||
shm_pool_finish_resize(pool);
|
||||
} else {
|
||||
pool->internal_refcount--;
|
||||
if (!(pool->internal_refcount >= 0))
|
||||
if (pool->internal_refcount < 0)
|
||||
wl_abort("Requested to unref an internal reference to "
|
||||
"pool but none found\n");
|
||||
|
||||
}
|
||||
|
||||
if (pool->internal_refcount + pool->external_refcount > 0)
|
||||
|
|
@ -166,13 +169,38 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external)
|
|||
free(pool);
|
||||
}
|
||||
|
||||
static void
|
||||
shm_buffer_unref(struct wl_shm_buffer *buffer, bool external)
|
||||
{
|
||||
if (external) {
|
||||
buffer->external_refcount--;
|
||||
if (buffer->external_refcount < 0) {
|
||||
wl_abort("Requested to unref an external reference to "
|
||||
"buffer but none found\n");
|
||||
}
|
||||
} else {
|
||||
buffer->internal_refcount--;
|
||||
if (buffer->internal_refcount < 0) {
|
||||
wl_abort("Requested to unref an internal reference to "
|
||||
"buffer but none found\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer->internal_refcount + buffer->external_refcount > 0)
|
||||
return;
|
||||
|
||||
if (buffer->client)
|
||||
wl_list_remove(&buffer->client_destroy_listener.link);
|
||||
shm_pool_unref(buffer->pool, false);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_buffer(struct wl_resource *resource)
|
||||
{
|
||||
struct wl_shm_buffer *buffer = wl_resource_get_user_data(resource);
|
||||
|
||||
shm_pool_unref(buffer->pool, false);
|
||||
free(buffer);
|
||||
shm_buffer_unref(buffer, false);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -206,6 +234,17 @@ format_is_supported(struct wl_client *client, uint32_t format)
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
shm_buffer_client_destroy_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct wl_shm_buffer *buffer =
|
||||
wl_container_of(listener, buffer, client_destroy_listener);
|
||||
|
||||
buffer->client = NULL;
|
||||
wl_list_remove(&buffer->client_destroy_listener.link);
|
||||
}
|
||||
|
||||
static void
|
||||
shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource,
|
||||
uint32_t id, int32_t offset,
|
||||
|
|
@ -238,6 +277,14 @@ shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource,
|
|||
return;
|
||||
}
|
||||
|
||||
buffer->client = client;
|
||||
buffer->client_destroy_listener.notify =
|
||||
shm_buffer_client_destroy_notify;
|
||||
wl_client_add_destroy_listener(buffer->client,
|
||||
&buffer->client_destroy_listener);
|
||||
|
||||
buffer->internal_refcount = 1;
|
||||
buffer->external_refcount = 0;
|
||||
buffer->width = width;
|
||||
buffer->height = height;
|
||||
buffer->format = format;
|
||||
|
|
@ -445,7 +492,7 @@ wl_shm_buffer_get(struct wl_resource *resource)
|
|||
}
|
||||
|
||||
WL_EXPORT int32_t
|
||||
wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer)
|
||||
wl_shm_buffer_get_stride(const struct wl_shm_buffer *buffer)
|
||||
{
|
||||
return buffer->stride;
|
||||
}
|
||||
|
|
@ -462,8 +509,8 @@ wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer)
|
|||
* SIGBUS signals. This can happen if the client claims that the
|
||||
* buffer is larger than it is or if something truncates the
|
||||
* underlying file. To prevent this signal from causing the compositor
|
||||
* to crash you should call wl_shm_buffer_begin_access and
|
||||
* wl_shm_buffer_end_access around code that reads from the memory.
|
||||
* to crash you should call wl_shm_buffer_begin_access() and
|
||||
* wl_shm_buffer_end_access() around code that reads from the memory.
|
||||
*
|
||||
* \memberof wl_shm_buffer
|
||||
*/
|
||||
|
|
@ -479,23 +526,62 @@ wl_shm_buffer_get_data(struct wl_shm_buffer *buffer)
|
|||
}
|
||||
|
||||
WL_EXPORT uint32_t
|
||||
wl_shm_buffer_get_format(struct wl_shm_buffer *buffer)
|
||||
wl_shm_buffer_get_format(const struct wl_shm_buffer *buffer)
|
||||
{
|
||||
return buffer->format;
|
||||
}
|
||||
|
||||
WL_EXPORT int32_t
|
||||
wl_shm_buffer_get_width(struct wl_shm_buffer *buffer)
|
||||
wl_shm_buffer_get_width(const struct wl_shm_buffer *buffer)
|
||||
{
|
||||
return buffer->width;
|
||||
}
|
||||
|
||||
WL_EXPORT int32_t
|
||||
wl_shm_buffer_get_height(struct wl_shm_buffer *buffer)
|
||||
wl_shm_buffer_get_height(const struct wl_shm_buffer *buffer)
|
||||
{
|
||||
return buffer->height;
|
||||
}
|
||||
|
||||
/** Reference a shm_buffer
|
||||
*
|
||||
* \param buffer The buffer object
|
||||
*
|
||||
* Returns a pointer to the buffer and increases the refcount.
|
||||
*
|
||||
* The compositor must remember to call wl_shm_buffer_unref() when
|
||||
* it no longer needs the reference to ensure proper destruction
|
||||
* of the buffer.
|
||||
*
|
||||
* \memberof wl_shm_buffer
|
||||
* \sa wl_shm_buffer_unref
|
||||
*/
|
||||
WL_EXPORT struct wl_shm_buffer *
|
||||
wl_shm_buffer_ref(struct wl_shm_buffer *buffer)
|
||||
{
|
||||
buffer->external_refcount++;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/** Unreference a shm_buffer
|
||||
*
|
||||
* \param buffer The buffer object
|
||||
*
|
||||
* Drops a reference to a buffer object.
|
||||
*
|
||||
* This is only necessary if the compositor has explicitly
|
||||
* taken a reference with wl_shm_buffer_ref(), otherwise
|
||||
* the buffer will be automatically destroyed when appropriate.
|
||||
*
|
||||
* \memberof wl_shm_buffer
|
||||
* \sa wl_shm_buffer_ref
|
||||
*/
|
||||
WL_EXPORT void
|
||||
wl_shm_buffer_unref(struct wl_shm_buffer *buffer)
|
||||
{
|
||||
shm_buffer_unref(buffer, true);
|
||||
}
|
||||
|
||||
/** Get a reference to a shm_buffer's shm_pool
|
||||
*
|
||||
* \param buffer The buffer object
|
||||
|
|
@ -503,7 +589,7 @@ wl_shm_buffer_get_height(struct wl_shm_buffer *buffer)
|
|||
* Returns a pointer to a buffer's shm_pool and increases the
|
||||
* shm_pool refcount.
|
||||
*
|
||||
* The compositor must remember to call wl_shm_pool_unref when
|
||||
* The compositor must remember to call wl_shm_pool_unref() when
|
||||
* it no longer needs the reference to ensure proper destruction
|
||||
* of the pool.
|
||||
*
|
||||
|
|
@ -513,10 +599,6 @@ wl_shm_buffer_get_height(struct wl_shm_buffer *buffer)
|
|||
WL_EXPORT struct wl_shm_pool *
|
||||
wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer)
|
||||
{
|
||||
if (!(buffer->pool->internal_refcount +
|
||||
buffer->pool->external_refcount))
|
||||
wl_abort("Can't get reference to pool that has been freed\n");
|
||||
|
||||
buffer->pool->external_refcount++;
|
||||
return buffer->pool;
|
||||
}
|
||||
|
|
@ -618,7 +700,7 @@ init_sigbus_data_key(void)
|
|||
* In order to make the compositor robust against clients that change
|
||||
* the size of the underlying file or lie about its size, you should
|
||||
* protect access to the buffer by calling this function before
|
||||
* reading from the memory and call wl_shm_buffer_end_access
|
||||
* reading from the memory and call wl_shm_buffer_end_access()
|
||||
* afterwards. This will install a signal handler for SIGBUS which
|
||||
* will prevent the compositor from crashing.
|
||||
*
|
||||
|
|
@ -629,15 +711,15 @@ init_sigbus_data_key(void)
|
|||
*
|
||||
* If a SIGBUS signal is received for an address within the range of
|
||||
* the SHM pool of the given buffer then the client will be sent an
|
||||
* error event when wl_shm_buffer_end_access is called. If the signal
|
||||
* error event when wl_shm_buffer_end_access() is called. If the signal
|
||||
* is for an address outside that range then the signal handler will
|
||||
* reraise the signal which would will likely cause the compositor to
|
||||
* terminate.
|
||||
*
|
||||
* It is safe to nest calls to these functions as long as the nested
|
||||
* calls are all accessing the same buffer. The number of calls to
|
||||
* wl_shm_buffer_end_access must match the number of calls to
|
||||
* wl_shm_buffer_begin_access. These functions are thread-safe and it
|
||||
* calls are all accessing the same pool. The number of calls to
|
||||
* wl_shm_buffer_end_access() must match the number of calls to
|
||||
* wl_shm_buffer_begin_access(). These functions are thread-safe and it
|
||||
* is allowed to simultaneously access different buffers or the same
|
||||
* buffer from multiple threads.
|
||||
*
|
||||
|
|
@ -671,11 +753,11 @@ wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer)
|
|||
sigbus_data->access_count++;
|
||||
}
|
||||
|
||||
/** Ends the access to a buffer started by wl_shm_buffer_begin_access
|
||||
/** Ends the access to a buffer started by wl_shm_buffer_begin_access()
|
||||
*
|
||||
* \param buffer The SHM buffer
|
||||
*
|
||||
* This should be called after wl_shm_buffer_begin_access once the
|
||||
* This should be called after wl_shm_buffer_begin_access() once the
|
||||
* buffer is no longer being accessed. If a SIGBUS signal was
|
||||
* generated in-between these two calls then the resource for the
|
||||
* given buffer will be sent an error.
|
||||
|
|
@ -698,9 +780,16 @@ wl_shm_buffer_end_access(struct wl_shm_buffer *buffer)
|
|||
|
||||
if (--sigbus_data->access_count == 0) {
|
||||
if (sigbus_data->fallback_mapping_used) {
|
||||
wl_resource_post_error(buffer->resource,
|
||||
WL_SHM_ERROR_INVALID_FD,
|
||||
"error accessing SHM buffer");
|
||||
if (buffer->resource) {
|
||||
wl_resource_post_error(buffer->resource,
|
||||
WL_SHM_ERROR_INVALID_FD,
|
||||
"error accessing SHM buffer");
|
||||
} else if (buffer->client) {
|
||||
wl_client_post_implementation_error(buffer->client,
|
||||
"Error accessing SHM buffer of a "
|
||||
"wl_buffer resource which has "
|
||||
"already been destroyed");
|
||||
}
|
||||
sigbus_data->fallback_mapping_used = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/** Deprecated attribute */
|
||||
#if __STDC_VERSION__ >= 202311L
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) || (defined(__cplusplus) && __cplusplus >= 201402L)
|
||||
#define WL_DEPRECATED [[deprecated]]
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||
#define WL_DEPRECATED __attribute__ ((deprecated))
|
||||
|
|
@ -70,7 +70,7 @@ extern "C" {
|
|||
#define WL_PRINTF(x, y)
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 202311L
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
|
||||
#define WL_TYPEOF(expr) typeof(expr)
|
||||
#else
|
||||
#define WL_TYPEOF(expr) __typeof__(expr)
|
||||
|
|
@ -90,6 +90,14 @@ extern "C" {
|
|||
*/
|
||||
struct wl_object;
|
||||
|
||||
/**
|
||||
* The maximum size of a protocol message.
|
||||
*
|
||||
* If a message size exceeds this value, the connection will be dropped.
|
||||
* Servers will send an invalid_method error before disconnecting.
|
||||
*/
|
||||
#define WL_MAX_MESSAGE_SIZE 4096
|
||||
|
||||
/**
|
||||
* Protocol message signature
|
||||
*
|
||||
|
|
@ -635,7 +643,7 @@ wl_fixed_to_double(wl_fixed_t f)
|
|||
static inline wl_fixed_t
|
||||
wl_fixed_from_double(double d)
|
||||
{
|
||||
return (wl_fixed_t) (d * 256.0);
|
||||
return (wl_fixed_t) (round(d * 256.0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -686,7 +686,7 @@ TEST(connection_marshal_big_enough)
|
|||
|
||||
TEST(connection_marshal_unbounded_boundary_size)
|
||||
{
|
||||
/* A string of lenth 8178 requires a buffer size of exactly 2^13. */
|
||||
/* A string of length 8178 requires a buffer size of exactly 2^13. */
|
||||
struct marshal_data data;
|
||||
char *big_string = malloc(8178);
|
||||
assert(big_string);
|
||||
|
|
|
|||
|
|
@ -901,6 +901,10 @@ enum wl_display_error {
|
|||
*/
|
||||
WL_DISPLAY_ERROR_NO_MEMORY = 2,
|
||||
};
|
||||
#endif /* WL_DISPLAY_ERROR_ENUM */
|
||||
|
||||
#ifndef WL_DISPLAY_ERROR_ENUM_IS_VALID
|
||||
#define WL_DISPLAY_ERROR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_display
|
||||
* Validate a wl_display error value.
|
||||
|
|
@ -921,7 +925,7 @@ wl_display_error_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_DISPLAY_ERROR_ENUM */
|
||||
#endif /* WL_DISPLAY_ERROR_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_display
|
||||
|
|
@ -1194,6 +1198,10 @@ enum wl_shm_error {
|
|||
*/
|
||||
WL_SHM_ERROR_INVALID_FD = 2,
|
||||
};
|
||||
#endif /* WL_SHM_ERROR_ENUM */
|
||||
|
||||
#ifndef WL_SHM_ERROR_ENUM_IS_VALID
|
||||
#define WL_SHM_ERROR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_shm
|
||||
* Validate a wl_shm error value.
|
||||
|
|
@ -1214,7 +1222,7 @@ wl_shm_error_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_SHM_ERROR_ENUM */
|
||||
#endif /* WL_SHM_ERROR_ENUM_IS_VALID */
|
||||
|
||||
#ifndef WL_SHM_FORMAT_ENUM
|
||||
#define WL_SHM_FORMAT_ENUM
|
||||
|
|
@ -1466,6 +1474,10 @@ enum wl_shm_format {
|
|||
*/
|
||||
WL_SHM_FORMAT_YVU444 = 0x34325659,
|
||||
};
|
||||
#endif /* WL_SHM_FORMAT_ENUM */
|
||||
|
||||
#ifndef WL_SHM_FORMAT_ENUM_IS_VALID
|
||||
#define WL_SHM_FORMAT_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_shm
|
||||
* Validate a wl_shm format value.
|
||||
|
|
@ -1596,7 +1608,7 @@ wl_shm_format_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_SHM_FORMAT_ENUM */
|
||||
#endif /* WL_SHM_FORMAT_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_shm
|
||||
|
|
@ -1706,6 +1718,10 @@ enum wl_data_offer_error {
|
|||
*/
|
||||
WL_DATA_OFFER_ERROR_INVALID_OFFER = 3,
|
||||
};
|
||||
#endif /* WL_DATA_OFFER_ERROR_ENUM */
|
||||
|
||||
#ifndef WL_DATA_OFFER_ERROR_ENUM_IS_VALID
|
||||
#define WL_DATA_OFFER_ERROR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_data_offer
|
||||
* Validate a wl_data_offer error value.
|
||||
|
|
@ -1728,7 +1744,7 @@ wl_data_offer_error_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_DATA_OFFER_ERROR_ENUM */
|
||||
#endif /* WL_DATA_OFFER_ERROR_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_data_offer
|
||||
|
|
@ -1940,6 +1956,10 @@ enum wl_data_source_error {
|
|||
*/
|
||||
WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1,
|
||||
};
|
||||
#endif /* WL_DATA_SOURCE_ERROR_ENUM */
|
||||
|
||||
#ifndef WL_DATA_SOURCE_ERROR_ENUM_IS_VALID
|
||||
#define WL_DATA_SOURCE_ERROR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_data_source
|
||||
* Validate a wl_data_source error value.
|
||||
|
|
@ -1958,7 +1978,7 @@ wl_data_source_error_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_DATA_SOURCE_ERROR_ENUM */
|
||||
#endif /* WL_DATA_SOURCE_ERROR_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_data_source
|
||||
|
|
@ -2130,6 +2150,10 @@ enum wl_data_device_error {
|
|||
*/
|
||||
WL_DATA_DEVICE_ERROR_ROLE = 0,
|
||||
};
|
||||
#endif /* WL_DATA_DEVICE_ERROR_ENUM */
|
||||
|
||||
#ifndef WL_DATA_DEVICE_ERROR_ENUM_IS_VALID
|
||||
#define WL_DATA_DEVICE_ERROR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_data_device
|
||||
* Validate a wl_data_device error value.
|
||||
|
|
@ -2146,7 +2170,7 @@ wl_data_device_error_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_DATA_DEVICE_ERROR_ENUM */
|
||||
#endif /* WL_DATA_DEVICE_ERROR_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_data_device
|
||||
|
|
@ -2387,6 +2411,10 @@ enum wl_data_device_manager_dnd_action {
|
|||
*/
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4,
|
||||
};
|
||||
#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */
|
||||
|
||||
#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM_IS_VALID
|
||||
#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_data_device_manager
|
||||
* Validate a wl_data_device_manager dnd_action value.
|
||||
|
|
@ -2407,7 +2435,7 @@ wl_data_device_manager_dnd_action_is_valid(uint32_t value, uint32_t version) {
|
|||
valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
|
||||
return (value & ~valid) == 0;
|
||||
}
|
||||
#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */
|
||||
#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_data_device_manager
|
||||
|
|
@ -2454,6 +2482,10 @@ enum wl_shell_error {
|
|||
*/
|
||||
WL_SHELL_ERROR_ROLE = 0,
|
||||
};
|
||||
#endif /* WL_SHELL_ERROR_ENUM */
|
||||
|
||||
#ifndef WL_SHELL_ERROR_ENUM_IS_VALID
|
||||
#define WL_SHELL_ERROR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_shell
|
||||
* Validate a wl_shell error value.
|
||||
|
|
@ -2470,7 +2502,7 @@ wl_shell_error_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_SHELL_ERROR_ENUM */
|
||||
#endif /* WL_SHELL_ERROR_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_shell
|
||||
|
|
@ -2549,6 +2581,10 @@ enum wl_shell_surface_resize {
|
|||
*/
|
||||
WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10,
|
||||
};
|
||||
#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
|
||||
|
||||
#ifndef WL_SHELL_SURFACE_RESIZE_ENUM_IS_VALID
|
||||
#define WL_SHELL_SURFACE_RESIZE_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_shell_surface
|
||||
* Validate a wl_shell_surface resize value.
|
||||
|
|
@ -2579,7 +2615,7 @@ wl_shell_surface_resize_is_valid(uint32_t value, uint32_t version) {
|
|||
valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;
|
||||
return (value & ~valid) == 0;
|
||||
}
|
||||
#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
|
||||
#endif /* WL_SHELL_SURFACE_RESIZE_ENUM_IS_VALID */
|
||||
|
||||
#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
|
||||
#define WL_SHELL_SURFACE_TRANSIENT_ENUM
|
||||
|
|
@ -2596,6 +2632,10 @@ enum wl_shell_surface_transient {
|
|||
*/
|
||||
WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1,
|
||||
};
|
||||
#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
|
||||
|
||||
#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM_IS_VALID
|
||||
#define WL_SHELL_SURFACE_TRANSIENT_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_shell_surface
|
||||
* Validate a wl_shell_surface transient value.
|
||||
|
|
@ -2610,7 +2650,7 @@ wl_shell_surface_transient_is_valid(uint32_t value, uint32_t version) {
|
|||
valid |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE;
|
||||
return (value & ~valid) == 0;
|
||||
}
|
||||
#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
|
||||
#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM_IS_VALID */
|
||||
|
||||
#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
|
||||
#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
|
||||
|
|
@ -2640,6 +2680,10 @@ enum wl_shell_surface_fullscreen_method {
|
|||
*/
|
||||
WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3,
|
||||
};
|
||||
#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
|
||||
|
||||
#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM_IS_VALID
|
||||
#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_shell_surface
|
||||
* Validate a wl_shell_surface fullscreen_method value.
|
||||
|
|
@ -2662,7 +2706,7 @@ wl_shell_surface_fullscreen_method_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
|
||||
#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_shell_surface
|
||||
|
|
@ -2994,6 +3038,10 @@ enum wl_surface_error {
|
|||
*/
|
||||
WL_SURFACE_ERROR_INVALID_TRANSFORM = 1,
|
||||
};
|
||||
#endif /* WL_SURFACE_ERROR_ENUM */
|
||||
|
||||
#ifndef WL_SURFACE_ERROR_ENUM_IS_VALID
|
||||
#define WL_SURFACE_ERROR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_surface
|
||||
* Validate a wl_surface error value.
|
||||
|
|
@ -3012,7 +3060,7 @@ wl_surface_error_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_SURFACE_ERROR_ENUM */
|
||||
#endif /* WL_SURFACE_ERROR_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_surface
|
||||
|
|
@ -3471,6 +3519,10 @@ enum wl_seat_capability {
|
|||
*/
|
||||
WL_SEAT_CAPABILITY_TOUCH = 4,
|
||||
};
|
||||
#endif /* WL_SEAT_CAPABILITY_ENUM */
|
||||
|
||||
#ifndef WL_SEAT_CAPABILITY_ENUM_IS_VALID
|
||||
#define WL_SEAT_CAPABILITY_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_seat
|
||||
* Validate a wl_seat capability value.
|
||||
|
|
@ -3489,7 +3541,7 @@ wl_seat_capability_is_valid(uint32_t value, uint32_t version) {
|
|||
valid |= WL_SEAT_CAPABILITY_TOUCH;
|
||||
return (value & ~valid) == 0;
|
||||
}
|
||||
#endif /* WL_SEAT_CAPABILITY_ENUM */
|
||||
#endif /* WL_SEAT_CAPABILITY_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_seat
|
||||
|
|
@ -3613,6 +3665,10 @@ enum wl_pointer_error {
|
|||
*/
|
||||
WL_POINTER_ERROR_ROLE = 0,
|
||||
};
|
||||
#endif /* WL_POINTER_ERROR_ENUM */
|
||||
|
||||
#ifndef WL_POINTER_ERROR_ENUM_IS_VALID
|
||||
#define WL_POINTER_ERROR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_pointer
|
||||
* Validate a wl_pointer error value.
|
||||
|
|
@ -3629,7 +3685,7 @@ wl_pointer_error_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_POINTER_ERROR_ENUM */
|
||||
#endif /* WL_POINTER_ERROR_ENUM_IS_VALID */
|
||||
|
||||
#ifndef WL_POINTER_BUTTON_STATE_ENUM
|
||||
#define WL_POINTER_BUTTON_STATE_ENUM
|
||||
|
|
@ -3650,6 +3706,10 @@ enum wl_pointer_button_state {
|
|||
*/
|
||||
WL_POINTER_BUTTON_STATE_PRESSED = 1,
|
||||
};
|
||||
#endif /* WL_POINTER_BUTTON_STATE_ENUM */
|
||||
|
||||
#ifndef WL_POINTER_BUTTON_STATE_ENUM_IS_VALID
|
||||
#define WL_POINTER_BUTTON_STATE_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_pointer
|
||||
* Validate a wl_pointer button_state value.
|
||||
|
|
@ -3668,7 +3728,7 @@ wl_pointer_button_state_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_POINTER_BUTTON_STATE_ENUM */
|
||||
#endif /* WL_POINTER_BUTTON_STATE_ENUM_IS_VALID */
|
||||
|
||||
#ifndef WL_POINTER_AXIS_ENUM
|
||||
#define WL_POINTER_AXIS_ENUM
|
||||
|
|
@ -3688,6 +3748,10 @@ enum wl_pointer_axis {
|
|||
*/
|
||||
WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
|
||||
};
|
||||
#endif /* WL_POINTER_AXIS_ENUM */
|
||||
|
||||
#ifndef WL_POINTER_AXIS_ENUM_IS_VALID
|
||||
#define WL_POINTER_AXIS_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_pointer
|
||||
* Validate a wl_pointer axis value.
|
||||
|
|
@ -3706,7 +3770,7 @@ wl_pointer_axis_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_POINTER_AXIS_ENUM */
|
||||
#endif /* WL_POINTER_AXIS_ENUM_IS_VALID */
|
||||
|
||||
#ifndef WL_POINTER_AXIS_SOURCE_ENUM
|
||||
#define WL_POINTER_AXIS_SOURCE_ENUM
|
||||
|
|
@ -3754,6 +3818,10 @@ enum wl_pointer_axis_source {
|
|||
* @ingroup iface_wl_pointer
|
||||
*/
|
||||
#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6
|
||||
#endif /* WL_POINTER_AXIS_SOURCE_ENUM */
|
||||
|
||||
#ifndef WL_POINTER_AXIS_SOURCE_ENUM_IS_VALID
|
||||
#define WL_POINTER_AXIS_SOURCE_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_pointer
|
||||
* Validate a wl_pointer axis_source value.
|
||||
|
|
@ -3776,7 +3844,7 @@ wl_pointer_axis_source_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_POINTER_AXIS_SOURCE_ENUM */
|
||||
#endif /* WL_POINTER_AXIS_SOURCE_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_pointer
|
||||
|
|
@ -4037,6 +4105,10 @@ enum wl_keyboard_keymap_format {
|
|||
*/
|
||||
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1,
|
||||
};
|
||||
#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
|
||||
|
||||
#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM_IS_VALID
|
||||
#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_keyboard
|
||||
* Validate a wl_keyboard keymap_format value.
|
||||
|
|
@ -4055,7 +4127,7 @@ wl_keyboard_keymap_format_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
|
||||
#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM_IS_VALID */
|
||||
|
||||
#ifndef WL_KEYBOARD_KEY_STATE_ENUM
|
||||
#define WL_KEYBOARD_KEY_STATE_ENUM
|
||||
|
|
@ -4075,6 +4147,10 @@ enum wl_keyboard_key_state {
|
|||
*/
|
||||
WL_KEYBOARD_KEY_STATE_PRESSED = 1,
|
||||
};
|
||||
#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
|
||||
|
||||
#ifndef WL_KEYBOARD_KEY_STATE_ENUM_IS_VALID
|
||||
#define WL_KEYBOARD_KEY_STATE_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_keyboard
|
||||
* Validate a wl_keyboard key_state value.
|
||||
|
|
@ -4093,7 +4169,7 @@ wl_keyboard_key_state_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
|
||||
#endif /* WL_KEYBOARD_KEY_STATE_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_keyboard
|
||||
|
|
@ -4419,6 +4495,10 @@ enum wl_output_subpixel {
|
|||
*/
|
||||
WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5,
|
||||
};
|
||||
#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
|
||||
|
||||
#ifndef WL_OUTPUT_SUBPIXEL_ENUM_IS_VALID
|
||||
#define WL_OUTPUT_SUBPIXEL_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_output
|
||||
* Validate a wl_output subpixel value.
|
||||
|
|
@ -4445,7 +4525,7 @@ wl_output_subpixel_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
|
||||
#endif /* WL_OUTPUT_SUBPIXEL_ENUM_IS_VALID */
|
||||
|
||||
#ifndef WL_OUTPUT_TRANSFORM_ENUM
|
||||
#define WL_OUTPUT_TRANSFORM_ENUM
|
||||
|
|
@ -4499,6 +4579,10 @@ enum wl_output_transform {
|
|||
*/
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7,
|
||||
};
|
||||
#endif /* WL_OUTPUT_TRANSFORM_ENUM */
|
||||
|
||||
#ifndef WL_OUTPUT_TRANSFORM_ENUM_IS_VALID
|
||||
#define WL_OUTPUT_TRANSFORM_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_output
|
||||
* Validate a wl_output transform value.
|
||||
|
|
@ -4529,7 +4613,7 @@ wl_output_transform_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_OUTPUT_TRANSFORM_ENUM */
|
||||
#endif /* WL_OUTPUT_TRANSFORM_ENUM_IS_VALID */
|
||||
|
||||
#ifndef WL_OUTPUT_MODE_ENUM
|
||||
#define WL_OUTPUT_MODE_ENUM
|
||||
|
|
@ -4550,6 +4634,10 @@ enum wl_output_mode {
|
|||
*/
|
||||
WL_OUTPUT_MODE_PREFERRED = 0x2,
|
||||
};
|
||||
#endif /* WL_OUTPUT_MODE_ENUM */
|
||||
|
||||
#ifndef WL_OUTPUT_MODE_ENUM_IS_VALID
|
||||
#define WL_OUTPUT_MODE_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_output
|
||||
* Validate a wl_output mode value.
|
||||
|
|
@ -4566,7 +4654,7 @@ wl_output_mode_is_valid(uint32_t value, uint32_t version) {
|
|||
valid |= WL_OUTPUT_MODE_PREFERRED;
|
||||
return (value & ~valid) == 0;
|
||||
}
|
||||
#endif /* WL_OUTPUT_MODE_ENUM */
|
||||
#endif /* WL_OUTPUT_MODE_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_output
|
||||
|
|
@ -4734,6 +4822,10 @@ enum wl_subcompositor_error {
|
|||
*/
|
||||
WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0,
|
||||
};
|
||||
#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
|
||||
|
||||
#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM_IS_VALID
|
||||
#define WL_SUBCOMPOSITOR_ERROR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_subcompositor
|
||||
* Validate a wl_subcompositor error value.
|
||||
|
|
@ -4750,7 +4842,7 @@ wl_subcompositor_error_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
|
||||
#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_subcompositor
|
||||
|
|
@ -4805,6 +4897,10 @@ enum wl_subsurface_error {
|
|||
*/
|
||||
WL_SUBSURFACE_ERROR_BAD_SURFACE = 0,
|
||||
};
|
||||
#endif /* WL_SUBSURFACE_ERROR_ENUM */
|
||||
|
||||
#ifndef WL_SUBSURFACE_ERROR_ENUM_IS_VALID
|
||||
#define WL_SUBSURFACE_ERROR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_wl_subsurface
|
||||
* Validate a wl_subsurface error value.
|
||||
|
|
@ -4821,7 +4917,7 @@ wl_subsurface_error_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* WL_SUBSURFACE_ERROR_ENUM */
|
||||
#endif /* WL_SUBSURFACE_ERROR_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_wl_subsurface
|
||||
|
|
|
|||
|
|
@ -107,6 +107,10 @@ enum intf_A_foo {
|
|||
* @ingroup iface_intf_A
|
||||
*/
|
||||
#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2
|
||||
#endif /* INTF_A_FOO_ENUM */
|
||||
|
||||
#ifndef INTF_A_FOO_ENUM_IS_VALID
|
||||
#define INTF_A_FOO_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_intf_A
|
||||
* Validate a intf_A foo value.
|
||||
|
|
@ -131,7 +135,7 @@ intf_A_foo_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* INTF_A_FOO_ENUM */
|
||||
#endif /* INTF_A_FOO_ENUM_IS_VALID */
|
||||
|
||||
#ifndef INTF_A_BAR_ENUM
|
||||
#define INTF_A_BAR_ENUM
|
||||
|
|
@ -154,6 +158,10 @@ enum intf_A_bar {
|
|||
* @ingroup iface_intf_A
|
||||
*/
|
||||
#define INTF_A_BAR_THIRD_SINCE_VERSION 2
|
||||
#endif /* INTF_A_BAR_ENUM */
|
||||
|
||||
#ifndef INTF_A_BAR_ENUM_IS_VALID
|
||||
#define INTF_A_BAR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_intf_A
|
||||
* Validate a intf_A bar value.
|
||||
|
|
@ -172,7 +180,7 @@ intf_A_bar_is_valid(uint32_t value, uint32_t version) {
|
|||
valid |= INTF_A_BAR_THIRD;
|
||||
return (value & ~valid) == 0;
|
||||
}
|
||||
#endif /* INTF_A_BAR_ENUM */
|
||||
#endif /* INTF_A_BAR_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_intf_A
|
||||
|
|
|
|||
|
|
@ -107,6 +107,10 @@ enum intf_A_foo {
|
|||
* @ingroup iface_intf_A
|
||||
*/
|
||||
#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2
|
||||
#endif /* INTF_A_FOO_ENUM */
|
||||
|
||||
#ifndef INTF_A_FOO_ENUM_IS_VALID
|
||||
#define INTF_A_FOO_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_intf_A
|
||||
* Validate a intf_A foo value.
|
||||
|
|
@ -131,7 +135,7 @@ intf_A_foo_is_valid(uint32_t value, uint32_t version) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* INTF_A_FOO_ENUM */
|
||||
#endif /* INTF_A_FOO_ENUM_IS_VALID */
|
||||
|
||||
#ifndef INTF_A_BAR_ENUM
|
||||
#define INTF_A_BAR_ENUM
|
||||
|
|
@ -154,6 +158,10 @@ enum intf_A_bar {
|
|||
* @ingroup iface_intf_A
|
||||
*/
|
||||
#define INTF_A_BAR_THIRD_SINCE_VERSION 2
|
||||
#endif /* INTF_A_BAR_ENUM */
|
||||
|
||||
#ifndef INTF_A_BAR_ENUM_IS_VALID
|
||||
#define INTF_A_BAR_ENUM_IS_VALID
|
||||
/**
|
||||
* @ingroup iface_intf_A
|
||||
* Validate a intf_A bar value.
|
||||
|
|
@ -172,7 +180,7 @@ intf_A_bar_is_valid(uint32_t value, uint32_t version) {
|
|||
valid |= INTF_A_BAR_THIRD;
|
||||
return (value & ~valid) == 0;
|
||||
}
|
||||
#endif /* INTF_A_BAR_ENUM */
|
||||
#endif /* INTF_A_BAR_ENUM_IS_VALID */
|
||||
|
||||
/**
|
||||
* @ingroup iface_intf_A
|
||||
|
|
|
|||
|
|
@ -924,7 +924,7 @@ TEST(versions)
|
|||
}
|
||||
|
||||
static void
|
||||
check_error_on_destroyed_object(void *data)
|
||||
check_error_on_destroyed_object(void)
|
||||
{
|
||||
struct client *c;
|
||||
struct wl_seat *seat;
|
||||
|
|
@ -1043,7 +1043,7 @@ TEST(filtered_global_is_hidden)
|
|||
1, d, bind_data_offer);
|
||||
wl_display_set_global_filter(d->wl_display, global_filter, NULL);
|
||||
|
||||
client_create_noarg(d, get_globals);
|
||||
client_create(d, get_globals, NULL);
|
||||
display_run(d);
|
||||
|
||||
wl_global_destroy(g);
|
||||
|
|
@ -1052,13 +1052,13 @@ TEST(filtered_global_is_hidden)
|
|||
}
|
||||
|
||||
static void
|
||||
get_dynamic_globals(void *data)
|
||||
get_dynamic_globals(void)
|
||||
{
|
||||
struct client *c = client_connect();
|
||||
struct wl_registry *registry;
|
||||
|
||||
registry = wl_display_get_registry(c->wl_display);
|
||||
wl_registry_add_listener(registry, ®istry_listener_filtered, data);
|
||||
wl_registry_add_listener(registry, ®istry_listener_filtered, NULL);
|
||||
wl_display_roundtrip(c->wl_display);
|
||||
|
||||
/* Wait for the server to create a new global */
|
||||
|
|
@ -1206,7 +1206,7 @@ static const struct wl_registry_listener zombie_fd_registry_listener = {
|
|||
};
|
||||
|
||||
static void
|
||||
zombie_client(void *data)
|
||||
zombie_client(void)
|
||||
{
|
||||
struct client *c = client_connect();
|
||||
struct wl_registry *registry;
|
||||
|
|
@ -1376,7 +1376,7 @@ static const struct wl_registry_listener double_zombie_fd_registry_listener = {
|
|||
};
|
||||
|
||||
static void
|
||||
double_zombie_client(void *data)
|
||||
double_zombie_client(void)
|
||||
{
|
||||
struct client *c = client_connect();
|
||||
struct wl_registry *registry;
|
||||
|
|
@ -1436,7 +1436,7 @@ static const struct wl_registry_listener bind_interface_mismatch_registry_listen
|
|||
};
|
||||
|
||||
static void
|
||||
registry_bind_interface_mismatch_client(void *data)
|
||||
registry_bind_interface_mismatch_client(void)
|
||||
{
|
||||
struct client *c = client_connect();
|
||||
struct wl_registry *registry;
|
||||
|
|
@ -1598,7 +1598,7 @@ static const struct wl_registry_listener global_remove_before_registry_listener
|
|||
};
|
||||
|
||||
static void
|
||||
global_remove_before_client(void *data)
|
||||
global_remove_before_client(void)
|
||||
{
|
||||
struct client *c = client_connect();
|
||||
struct wl_registry *registry;
|
||||
|
|
@ -1648,7 +1648,7 @@ static const struct wl_registry_listener global_remove_after_registry_listener =
|
|||
};
|
||||
|
||||
static void
|
||||
global_remove_after_client(void *data)
|
||||
global_remove_after_client(void)
|
||||
{
|
||||
struct client *c = client_connect();
|
||||
struct wl_registry *registry;
|
||||
|
|
@ -1695,6 +1695,75 @@ TEST(global_remove)
|
|||
display_destroy(d);
|
||||
}
|
||||
|
||||
static void
|
||||
dispatch_single_read_events(struct wl_display *d)
|
||||
{
|
||||
if (wl_display_prepare_read(d) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
do {
|
||||
ret = wl_display_flush(d);
|
||||
} while (ret < 0 && (errno == EINTR || errno == EAGAIN));
|
||||
assert(ret >= 0);
|
||||
|
||||
struct pollfd pfd[1];
|
||||
pfd[0].fd = wl_display_get_fd(d);
|
||||
pfd[0].events = POLLIN;
|
||||
|
||||
do {
|
||||
ret = poll(pfd, 1, -1);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
assert(ret > 0);
|
||||
|
||||
wl_display_read_events(d);
|
||||
}
|
||||
|
||||
static void
|
||||
dispatch_single_client(void)
|
||||
{
|
||||
struct client *c = client_connect();
|
||||
|
||||
assert(wl_display_dispatch_pending_single(c->wl_display) == 0);
|
||||
|
||||
struct wl_registry *registry = wl_display_get_registry(c->wl_display);
|
||||
|
||||
dispatch_single_read_events(c->wl_display);
|
||||
|
||||
// [1815110.061] {Default Queue} wl_registry#3.global(1, "test", 1)
|
||||
assert(wl_display_dispatch_pending_single(c->wl_display) == 1);
|
||||
|
||||
dispatch_single_read_events(c->wl_display);
|
||||
|
||||
// [1815110.067] {Default Queue} wl_registry#3.global(2, "wl_seat", 1)
|
||||
assert(wl_display_dispatch_pending_single(c->wl_display) == 1);
|
||||
|
||||
// No more events
|
||||
assert(wl_display_dispatch_pending_single(c->wl_display) == 0);
|
||||
|
||||
wl_registry_destroy(registry);
|
||||
|
||||
client_disconnect(c);
|
||||
}
|
||||
|
||||
TEST(dispatch_single)
|
||||
{
|
||||
struct display *d = display_create();
|
||||
|
||||
struct wl_global *global = wl_global_create(d->wl_display,
|
||||
&wl_seat_interface,
|
||||
1, d, bind_seat);
|
||||
|
||||
client_create_noarg(d, dispatch_single_client);
|
||||
|
||||
display_run(d);
|
||||
|
||||
wl_global_destroy(global);
|
||||
|
||||
display_destroy(d);
|
||||
}
|
||||
|
||||
static void
|
||||
terminate_display(void *arg)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ tests_protocol_c = custom_target(
|
|||
output: 'tests-protocol.c'
|
||||
)
|
||||
|
||||
executable(
|
||||
exec_fd_leak_checker = executable(
|
||||
'exec-fd-leak-checker',
|
||||
'exec-fd-leak-checker.c',
|
||||
dependencies: test_runner_dep
|
||||
|
|
@ -96,78 +96,116 @@ if get_option('scanner')
|
|||
endif
|
||||
|
||||
tests = {
|
||||
'array-test': [],
|
||||
'client-test': [ wayland_server_protocol_h ],
|
||||
'display-test': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
tests_server_protocol_h,
|
||||
tests_client_protocol_c,
|
||||
tests_protocol_c,
|
||||
],
|
||||
'connection-test': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
'event-loop-test': [ wayland_server_protocol_h ],
|
||||
'fixed-test': [],
|
||||
'interface-test': [ wayland_client_protocol_h ],
|
||||
'list-test': [],
|
||||
'map-test': [],
|
||||
'sanity-test' : [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
'socket-test': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
'queue-test': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
'signal-test': [ wayland_server_protocol_h ],
|
||||
'newsignal-test': [
|
||||
# wayland-server.c is needed here to access wl_priv_* functions
|
||||
files('../src/wayland-server.c'),
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
'resources-test': [ wayland_server_protocol_h ],
|
||||
'message-test': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
'compositor-introspection-test': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
'protocol-logger-test': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
'headers-test': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
'headers-protocol-test.c',
|
||||
wayland_client_protocol_core_h,
|
||||
wayland_server_protocol_core_h,
|
||||
'headers-protocol-core-test.c',
|
||||
],
|
||||
'os-wrappers-test': [],
|
||||
'proxy-test': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
'enum-validator-test': [],
|
||||
'array-test': {},
|
||||
'client-test': {
|
||||
'extra_sources': [ wayland_server_protocol_h ],
|
||||
},
|
||||
'display-test': {
|
||||
'extra_sources': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
tests_server_protocol_h,
|
||||
tests_client_protocol_c,
|
||||
tests_protocol_c,
|
||||
],
|
||||
},
|
||||
'connection-test': {
|
||||
'extra_sources': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
},
|
||||
'event-loop-test': {
|
||||
'extra_sources': [ wayland_server_protocol_h ],
|
||||
},
|
||||
'fixed-test': {},
|
||||
'interface-test': {
|
||||
'extra_sources': [ wayland_client_protocol_h ],
|
||||
},
|
||||
'list-test': {},
|
||||
'map-test': {},
|
||||
'sanity-test' : {
|
||||
'extra_sources': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
'runtime_deps': [ exec_fd_leak_checker ],
|
||||
},
|
||||
'socket-test': {
|
||||
'extra_sources': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
},
|
||||
'queue-test': {
|
||||
'extra_sources': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
},
|
||||
'signal-test': {
|
||||
'extra_sources': [ wayland_server_protocol_h ],
|
||||
},
|
||||
'newsignal-test': {
|
||||
'extra_sources': [
|
||||
# wayland-server.c is needed here to access wl_priv_* functions
|
||||
files('../src/wayland-server.c'),
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
},
|
||||
'resources-test': {
|
||||
'extra_sources': [ wayland_server_protocol_h ],
|
||||
},
|
||||
'message-test': {
|
||||
'extra_sources': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
},
|
||||
'compositor-introspection-test': {
|
||||
'extra_sources': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
},
|
||||
'protocol-logger-test': {
|
||||
'extra_sources': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
},
|
||||
'headers-test': {
|
||||
'extra_sources': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
'headers-protocol-test.c',
|
||||
wayland_client_protocol_core_h,
|
||||
wayland_server_protocol_core_h,
|
||||
'headers-protocol-core-test.c',
|
||||
],
|
||||
},
|
||||
'os-wrappers-test': {
|
||||
'runtime_deps': [ exec_fd_leak_checker ],
|
||||
},
|
||||
'proxy-test': {
|
||||
'extra_sources': [
|
||||
wayland_client_protocol_h,
|
||||
wayland_server_protocol_h,
|
||||
],
|
||||
},
|
||||
'enum-validator-test': {},
|
||||
}
|
||||
|
||||
foreach test_name, test_extra_sources: tests
|
||||
foreach test_name, test_extras : tests
|
||||
test_extra_sources = test_extras.get('extra_sources', [])
|
||||
test_runtime_deps = test_extras.get('runtime_deps', [])
|
||||
test_sources = [ test_name + '.c' ] + test_extra_sources
|
||||
test_deps = [test_runner_dep, epoll_dep]
|
||||
bin = executable(test_name, test_sources, dependencies: test_deps)
|
||||
test(
|
||||
test_name,
|
||||
bin,
|
||||
depends: test_runtime_deps,
|
||||
env: [
|
||||
'TEST_SRC_DIR=@0@'.format(meson.current_source_dir()),
|
||||
'TEST_BUILD_DIR=@0@'.format(meson.current_build_dir()),
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "wayland-server.h"
|
||||
#include "test-runner.h"
|
||||
#include "test-compositor.h"
|
||||
#include "../src/timespec-util.h"
|
||||
|
||||
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
|
||||
|
||||
|
|
@ -571,6 +572,68 @@ client_test_queue_names(void)
|
|||
wl_display_disconnect(display);
|
||||
}
|
||||
|
||||
static void
|
||||
dispatch_timeout_sync_callback(void *data, struct wl_callback *callback,
|
||||
uint32_t serial)
|
||||
{
|
||||
bool *done = data;
|
||||
|
||||
*done = true;
|
||||
wl_callback_destroy(callback);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener dispatch_timeout_sync_listener = {
|
||||
dispatch_timeout_sync_callback
|
||||
};
|
||||
|
||||
static void
|
||||
client_test_queue_dispatch_simple(void)
|
||||
{
|
||||
struct wl_display *display;
|
||||
struct timespec timeout;
|
||||
struct wl_callback *callback;
|
||||
bool done = false;
|
||||
int ret = 0;
|
||||
|
||||
display = wl_display_connect(NULL);
|
||||
assert(display);
|
||||
|
||||
callback = wl_display_sync(display);
|
||||
assert(callback != NULL);
|
||||
wl_callback_add_listener(callback, &dispatch_timeout_sync_listener, &done);
|
||||
|
||||
timespec_from_msec(&timeout, 1000);
|
||||
|
||||
while (!done) {
|
||||
ret = wl_display_dispatch_timeout(display, &timeout);
|
||||
assert(ret > 0);
|
||||
}
|
||||
|
||||
wl_display_disconnect(display);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
client_test_queue_dispatch_timeout(void)
|
||||
{
|
||||
struct wl_display *display;
|
||||
struct timespec timeout;
|
||||
int ret = 0;
|
||||
|
||||
display = wl_display_connect(NULL);
|
||||
assert(display);
|
||||
|
||||
timespec_from_msec(&timeout, 100);
|
||||
|
||||
ret = wl_display_dispatch_timeout(display, &timeout);
|
||||
assert(ret == 0);
|
||||
|
||||
wl_display_disconnect(display);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_bind(struct wl_client *client,
|
||||
void *data, uint32_t version, uint32_t id)
|
||||
|
|
@ -709,3 +772,27 @@ TEST(queue_names)
|
|||
|
||||
display_destroy(d);
|
||||
}
|
||||
|
||||
TEST(queue_dispatch_simple)
|
||||
{
|
||||
struct display *d = display_create();
|
||||
|
||||
test_set_timeout(2);
|
||||
|
||||
client_create_noarg(d, client_test_queue_dispatch_simple);
|
||||
display_run(d);
|
||||
|
||||
display_destroy(d);
|
||||
}
|
||||
|
||||
TEST(queue_dispatch_timeout)
|
||||
{
|
||||
struct display *d = display_create();
|
||||
|
||||
test_set_timeout(2);
|
||||
|
||||
client_create_noarg(d, client_test_queue_dispatch_timeout);
|
||||
display_run(d);
|
||||
|
||||
display_destroy(d);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -507,7 +507,7 @@ static const struct wl_registry_listener registry_listener =
|
|||
NULL
|
||||
};
|
||||
|
||||
struct client *client_connect()
|
||||
struct client *client_connect(void)
|
||||
{
|
||||
struct wl_registry *reg;
|
||||
struct client *c = calloc(1, sizeof *c);
|
||||
|
|
|
|||
|
|
@ -118,5 +118,17 @@ struct client_info *client_create_with_name(struct display *d,
|
|||
void *data,
|
||||
const char *name);
|
||||
#define client_create(d, c, data) client_create_with_name((d), (c), data, (#c))
|
||||
static inline void noarg_cb(void *data)
|
||||
{
|
||||
void (*cb)(void) = data;
|
||||
cb();
|
||||
}
|
||||
static inline struct client_info *client_create_with_name_noarg(struct display *d,
|
||||
void (*client_main)(void),
|
||||
const char *name)
|
||||
{
|
||||
return client_create_with_name(d, noarg_cb, client_main, name);
|
||||
}
|
||||
|
||||
#define client_create_noarg(d, c) \
|
||||
client_create_with_name((d), (void(*)(void *)) (c), NULL, (#c))
|
||||
client_create_with_name_noarg((d), (c), (#c))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue