mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-10-29 05:40:16 -04:00
Compare commits
24 commits
b362e8fb4f
...
7ff7d3e354
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ff7d3e354 | ||
|
|
8198e0c827 | ||
|
|
d81525a235 | ||
|
|
4673ef7e9c | ||
|
|
77730f10a0 | ||
|
|
264da6a92b | ||
|
|
cd0d1543c0 | ||
|
|
90187031e6 | ||
|
|
eecf3f7635 | ||
|
|
adf84614ca | ||
|
|
ba9f9a446f | ||
|
|
53fbc2b0c1 | ||
|
|
fdac631d17 | ||
|
|
6c1da92018 | ||
|
|
ca83185e8a | ||
|
|
4a0c4e2119 | ||
|
|
387adc6a79 | ||
|
|
0de833da29 | ||
|
|
2978fd701a | ||
|
|
5c2f31d8d6 | ||
|
|
ce0ac4f29e | ||
|
|
1bee7aa4a7 | ||
|
|
6281ccbd3d | ||
|
|
ecff0ee10c |
17 changed files with 639 additions and 101 deletions
|
|
@ -43,7 +43,7 @@ include:
|
||||||
# API changes. If you need new features from ci-templates you must bump
|
# 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
|
# 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.
|
# be aware that you may need to account for API changes when doing so.
|
||||||
ref: f210ea84576f756816da37908771edcee14ef7e6
|
ref: 48c2c583a865bd59be21e8938df247faf460099c
|
||||||
file:
|
file:
|
||||||
- '/templates/debian.yml'
|
- '/templates/debian.yml'
|
||||||
- '/templates/freebsd.yml'
|
- '/templates/freebsd.yml'
|
||||||
|
|
@ -306,11 +306,11 @@ armv7-release-debian-build:
|
||||||
.os-freebsd:
|
.os-freebsd:
|
||||||
variables:
|
variables:
|
||||||
BUILD_OS: freebsd
|
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'
|
FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2'
|
||||||
# bump this tag every time you change something which requires rebuilding the
|
# bump this tag every time you change something which requires rebuilding the
|
||||||
# base image
|
# 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
|
# Don't build documentation since installing the required tools massively
|
||||||
# increases the VM image (and therefore container) size.
|
# increases the VM image (and therefore container) size.
|
||||||
MESON_ARGS: "--fatal-meson-warnings -Dwerror=true -Ddocumentation=false"
|
MESON_ARGS: "--fatal-meson-warnings -Dwerror=true -Ddocumentation=false"
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "xcursor.h"
|
#include "xcursor.h"
|
||||||
#include "wayland-cursor.h"
|
#include "wayland-cursor.h"
|
||||||
#include "wayland-client.h"
|
#include "wayland-client.h"
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
@ -284,7 +285,8 @@ wl_cursor_create_from_xcursor_images(struct xcursor_images *images,
|
||||||
{
|
{
|
||||||
struct cursor *cursor;
|
struct cursor *cursor;
|
||||||
struct cursor_image *image;
|
struct cursor_image *image;
|
||||||
int i, size;
|
size_t size;
|
||||||
|
int i;
|
||||||
|
|
||||||
cursor = malloc(sizeof *cursor);
|
cursor = malloc(sizeof *cursor);
|
||||||
if (!cursor)
|
if (!cursor)
|
||||||
|
|
@ -314,7 +316,12 @@ wl_cursor_create_from_xcursor_images(struct xcursor_images *images,
|
||||||
image->image.hotspot_y = images->images[i]->yhot;
|
image->image.hotspot_y = images->images[i]->yhot;
|
||||||
image->image.delay = images->images[i]->delay;
|
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);
|
image->offset = shm_pool_allocate(theme->pool, size);
|
||||||
if (image->offset < 0) {
|
if (image->offset < 0) {
|
||||||
free(image);
|
free(image);
|
||||||
|
|
@ -344,6 +351,8 @@ load_callback(struct xcursor_images *images, void *data)
|
||||||
{
|
{
|
||||||
struct wl_cursor_theme *theme = data;
|
struct wl_cursor_theme *theme = data;
|
||||||
struct wl_cursor *cursor;
|
struct wl_cursor *cursor;
|
||||||
|
struct wl_cursor **p;
|
||||||
|
size_t s;
|
||||||
|
|
||||||
if (wl_cursor_theme_get_cursor(theme, images->name)) {
|
if (wl_cursor_theme_get_cursor(theme, images->name)) {
|
||||||
xcursor_images_destroy(images);
|
xcursor_images_destroy(images);
|
||||||
|
|
@ -353,15 +362,14 @@ load_callback(struct xcursor_images *images, void *data)
|
||||||
cursor = wl_cursor_create_from_xcursor_images(images, theme);
|
cursor = wl_cursor_create_from_xcursor_images(images, theme);
|
||||||
|
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
theme->cursor_count++;
|
s = theme->cursor_count + 1;
|
||||||
theme->cursors =
|
p = realloc(theme->cursors, s * sizeof theme->cursors[0]);
|
||||||
realloc(theme->cursors,
|
|
||||||
theme->cursor_count * sizeof theme->cursors[0]);
|
|
||||||
|
|
||||||
if (theme->cursors == NULL) {
|
if (p == NULL) {
|
||||||
theme->cursor_count--;
|
|
||||||
free(cursor);
|
free(cursor);
|
||||||
} else {
|
} else {
|
||||||
|
theme->cursor_count = s;
|
||||||
|
theme->cursors = p;
|
||||||
theme->cursors[theme->cursor_count - 1] = cursor;
|
theme->cursors[theme->cursor_count - 1] = cursor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -389,6 +397,9 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
|
||||||
if (!theme)
|
if (!theme)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (size < 0 || (size > 0 && INT_MAX / size / 4 < size))
|
||||||
|
goto err;
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
name = "default";
|
name = "default";
|
||||||
|
|
||||||
|
|
@ -398,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);
|
theme->pool = shm_pool_create(shm, size * size * 4);
|
||||||
if (!theme->pool)
|
if (!theme->pool)
|
||||||
goto out_error_pool;
|
goto err;
|
||||||
|
|
||||||
xcursor_load_theme(name, size, load_callback, theme);
|
xcursor_load_theme(name, size, load_callback, theme);
|
||||||
|
|
||||||
|
|
@ -410,7 +421,7 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
|
||||||
|
|
||||||
return theme;
|
return theme;
|
||||||
|
|
||||||
out_error_pool:
|
err:
|
||||||
free(theme);
|
free(theme);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -259,6 +259,8 @@ xcursor_read_file_header(FILE *file)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!xcursor_read_uint(file, &head.ntoc))
|
if (!xcursor_read_uint(file, &head.ntoc))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (head.header < XCURSOR_FILE_HEADER_LEN)
|
||||||
|
return NULL;
|
||||||
skip = head.header - XCURSOR_FILE_HEADER_LEN;
|
skip = head.header - XCURSOR_FILE_HEADER_LEN;
|
||||||
if (skip)
|
if (skip)
|
||||||
if (fseek(file, skip, SEEK_CUR) == EOF)
|
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,
|
* add space for any needed directory separators, one per component,
|
||||||
* and one for the trailing null
|
* 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);
|
full = malloc(full_size);
|
||||||
if (!full)
|
if (!full)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -686,11 +688,15 @@ load_all_cursors_from_dir(const char *path, int size,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
DIR *dir = opendir(path);
|
DIR *dir;
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
char *full;
|
char *full;
|
||||||
struct xcursor_images *images;
|
struct xcursor_images *images;
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dir = opendir(path);
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
||||||
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>
|
||||||
|
|
@ -97,7 +97,9 @@
|
||||||
in the environment). Beginning in Wayland 1.15, implementations can
|
in the environment). Beginning in Wayland 1.15, implementations can
|
||||||
optionally support server socket endpoints located at arbitrary
|
optionally support server socket endpoints located at arbitrary
|
||||||
locations in the filesystem by setting <emphasis>WAYLAND_DISPLAY</emphasis>
|
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>
|
||||||
<para>
|
<para>
|
||||||
Every message is structured as 32-bit words; values are represented in the
|
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="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="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="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="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="Client.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||||
<xi:include href="Server.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',
|
'Protocol.xml',
|
||||||
'Xwayland.xml',
|
'Xwayland.xml',
|
||||||
'Compositors.xml',
|
'Compositors.xml',
|
||||||
|
'Color.xml',
|
||||||
'Client.xml',
|
'Client.xml',
|
||||||
'Server.xml'
|
'Server.xml'
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ if get_option('tests')
|
||||||
test(
|
test(
|
||||||
'wayland-egl symbols check',
|
'wayland-egl symbols check',
|
||||||
find_program('wayland-egl-symbols-check'),
|
find_program('wayland-egl-symbols-check'),
|
||||||
|
depends: wayland_egl,
|
||||||
env: [
|
env: [
|
||||||
'WAYLAND_EGL_LIB=@0@'.format(wayland_egl_shared.full_path()),
|
'WAYLAND_EGL_LIB=@0@'.format(wayland_egl_shared.full_path()),
|
||||||
'NM=@0@'.format(nm_path)
|
'NM=@0@'.format(nm_path)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
project(
|
project(
|
||||||
'wayland', 'c',
|
'wayland', 'c',
|
||||||
version: '1.23.91',
|
version: '1.24.90',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>= 0.57.0',
|
meson_version: '>= 0.57.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
|
|
@ -46,6 +46,7 @@ have_funcs = [
|
||||||
'memfd_create',
|
'memfd_create',
|
||||||
'mremap',
|
'mremap',
|
||||||
'strndup',
|
'strndup',
|
||||||
|
'gettid',
|
||||||
]
|
]
|
||||||
foreach f: have_funcs
|
foreach f: have_funcs
|
||||||
config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f))
|
config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f))
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "../config.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
@ -1491,16 +1493,61 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
|
||||||
return result;
|
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
|
void
|
||||||
wl_closure_print(struct wl_closure *closure, struct wl_object *target,
|
wl_closure_print(struct wl_closure *closure, struct wl_object *target,
|
||||||
int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg),
|
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;
|
int i;
|
||||||
struct argument_details arg;
|
struct argument_details arg;
|
||||||
const char *signature = closure->message->signature;
|
const char *signature = closure->message->signature;
|
||||||
struct timespec tp;
|
struct timespec tp;
|
||||||
unsigned int time;
|
uint64_t time;
|
||||||
uint32_t nval;
|
uint32_t nval;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
|
@ -1511,18 +1558,41 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clock_gettime(CLOCK_REALTIME, &tp);
|
clock_gettime(CLOCK_REALTIME, &tp);
|
||||||
time = (tp.tv_sec * 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));
|
||||||
|
|
||||||
fprintf(f, "[%7u.%03u] ", time / 1000, time % 1000);
|
#if defined(HAVE_GETTID)
|
||||||
|
if (include_tid < 0) {
|
||||||
|
include_tid = wl_check_env_token(getenv("WAYLAND_DEBUG"), "thread_id");
|
||||||
|
}
|
||||||
|
|
||||||
if (queue_name)
|
if (include_tid) {
|
||||||
fprintf(f, "{%s} ", queue_name);
|
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 " : "",
|
discarded ? "discarded " : "",
|
||||||
|
color ? WL_DEBUG_COLOR_RESET : "",
|
||||||
send ? " -> " : "",
|
send ? " -> " : "",
|
||||||
target->interface->name, target->id,
|
color ? WL_DEBUG_COLOR_BLUE : "",
|
||||||
closure->message->name);
|
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++) {
|
for (i = 0; i < closure->count; i++) {
|
||||||
signature = get_next_argument(signature, &arg);
|
signature = get_next_argument(signature, &arg);
|
||||||
|
|
@ -1587,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) {
|
if (fclose(f) == 0) {
|
||||||
fprintf(stderr, "%s", buffer);
|
fprintf(stderr, "%s", buffer);
|
||||||
|
|
|
||||||
|
|
@ -268,9 +268,16 @@ int
|
||||||
wl_display_dispatch_queue_pending(struct wl_display *display,
|
wl_display_dispatch_queue_pending(struct wl_display *display,
|
||||||
struct wl_event_queue *queue);
|
struct wl_event_queue *queue);
|
||||||
|
|
||||||
|
int
|
||||||
|
wl_display_dispatch_queue_pending_single(struct wl_display *display,
|
||||||
|
struct wl_event_queue *queue);
|
||||||
|
|
||||||
int
|
int
|
||||||
wl_display_dispatch_pending(struct wl_display *display);
|
wl_display_dispatch_pending(struct wl_display *display);
|
||||||
|
|
||||||
|
int
|
||||||
|
wl_display_dispatch_pending_single(struct wl_display *display);
|
||||||
|
|
||||||
int
|
int
|
||||||
wl_display_get_error(struct wl_display *display);
|
wl_display_get_error(struct wl_display *display);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ struct wl_display {
|
||||||
/** \endcond */
|
/** \endcond */
|
||||||
|
|
||||||
static int debug_client = 0;
|
static int debug_client = 0;
|
||||||
|
static int debug_color = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This helper function wakes up all threads that are
|
* This helper function wakes up all threads that are
|
||||||
|
|
@ -936,7 +937,7 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
|
||||||
queue_name = wl_event_queue_get_name(queue);
|
queue_name = wl_event_queue_get_name(queue);
|
||||||
|
|
||||||
wl_closure_print(closure, &proxy->object, true, false, NULL,
|
wl_closure_print(closure, &proxy->object, true, false, NULL,
|
||||||
queue_name);
|
queue_name, debug_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wl_closure_send(closure, proxy->display->connection)) {
|
if (wl_closure_send(closure, proxy->display->connection)) {
|
||||||
|
|
@ -1229,10 +1230,23 @@ wl_display_connect_to_fd(int fd)
|
||||||
{
|
{
|
||||||
struct wl_display *display;
|
struct wl_display *display;
|
||||||
const char *debug;
|
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");
|
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;
|
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);
|
display = zalloc(sizeof *display);
|
||||||
if (display == NULL) {
|
if (display == NULL) {
|
||||||
|
|
@ -1564,6 +1578,28 @@ queue_event(struct wl_display *display, int len)
|
||||||
id = p[0];
|
id = p[0];
|
||||||
opcode = p[1] & 0xffff;
|
opcode = p[1] & 0xffff;
|
||||||
size = p[1] >> 16;
|
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)
|
if (len < size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
@ -1578,12 +1614,16 @@ queue_event(struct wl_display *display, int len)
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
clock_gettime(CLOCK_REALTIME, &tp);
|
clock_gettime(CLOCK_REALTIME, &tp);
|
||||||
time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
|
time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
|
||||||
|
fprintf(stderr, "%s[%7u.%03u] %sdiscarded %s[%s]%s#%u%s.[event %d]%s"
|
||||||
fprintf(stderr, "[%7u.%03u] discarded [%s]#%d.[event %d]"
|
|
||||||
"(%d fd, %d byte)\n",
|
"(%d fd, %d byte)\n",
|
||||||
|
debug_color ? WL_DEBUG_COLOR_GREEN : "",
|
||||||
time / 1000, time % 1000,
|
time / 1000, time % 1000,
|
||||||
|
debug_color ? WL_DEBUG_COLOR_RED : "",
|
||||||
|
debug_color ? WL_DEBUG_COLOR_BLUE : "",
|
||||||
zombie ? "zombie" : "unknown",
|
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);
|
num_zombie_fds, size);
|
||||||
}
|
}
|
||||||
if (num_zombie_fds > 0)
|
if (num_zombie_fds > 0)
|
||||||
|
|
@ -1668,7 +1708,7 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
|
||||||
!(proxy->dispatcher || proxy->object.implementation);
|
!(proxy->dispatcher || proxy->object.implementation);
|
||||||
|
|
||||||
wl_closure_print(closure, &proxy->object, false, discarded,
|
wl_closure_print(closure, &proxy->object, false, discarded,
|
||||||
id_from_object, queue->name);
|
id_from_object, queue->name, debug_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proxy_destroyed) {
|
if (proxy_destroyed) {
|
||||||
|
|
@ -1842,6 +1882,34 @@ err:
|
||||||
return -1;
|
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
|
/** Prepare to read events from the display's file descriptor to a queue
|
||||||
*
|
*
|
||||||
* \param display The display context object
|
* \param display The display context object
|
||||||
|
|
@ -2172,6 +2240,34 @@ wl_display_dispatch_queue_pending(struct wl_display *display,
|
||||||
return ret;
|
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
|
/** Process incoming events
|
||||||
*
|
*
|
||||||
* \param display The display context object
|
* \param display The display context object
|
||||||
|
|
@ -2232,6 +2328,25 @@ wl_display_dispatch_pending(struct wl_display *display)
|
||||||
&display->default_queue);
|
&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
|
/** Retrieve the last error that occurred on a display
|
||||||
*
|
*
|
||||||
* \param display The display context object
|
* \param display The display context object
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,17 @@
|
||||||
#define WL_CLOSURE_MAX_ARGS 20
|
#define WL_CLOSURE_MAX_ARGS 20
|
||||||
#define WL_BUFFER_DEFAULT_SIZE_POT 12
|
#define WL_BUFFER_DEFAULT_SIZE_POT 12
|
||||||
#define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT)
|
#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.
|
* Argument types used in signatures.
|
||||||
|
|
@ -226,11 +237,14 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
|
||||||
int
|
int
|
||||||
wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection);
|
wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection);
|
||||||
|
|
||||||
|
bool
|
||||||
|
wl_check_env_token(const char *env, const char *token);
|
||||||
|
|
||||||
void
|
void
|
||||||
wl_closure_print(struct wl_closure *closure,
|
wl_closure_print(struct wl_closure *closure,
|
||||||
struct wl_object *target, int send, int discarded,
|
struct wl_object *target, int send, int discarded,
|
||||||
uint32_t (*n_parse)(union wl_argument *arg),
|
uint32_t (*n_parse)(union wl_argument *arg),
|
||||||
const char *queue_name);
|
const char *queue_name, int color);
|
||||||
|
|
||||||
void
|
void
|
||||||
wl_closure_destroy(struct wl_closure *closure);
|
wl_closure_destroy(struct wl_closure *closure);
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,7 @@ struct wl_protocol_logger {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int debug_server = 0;
|
static int debug_server = 0;
|
||||||
|
static int debug_color = 0;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
log_closure(struct wl_resource *resource,
|
log_closure(struct wl_resource *resource,
|
||||||
|
|
@ -160,7 +161,7 @@ log_closure(struct wl_resource *resource,
|
||||||
struct wl_protocol_logger_message message;
|
struct wl_protocol_logger_message message;
|
||||||
|
|
||||||
if (debug_server)
|
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)) {
|
if (!wl_list_empty(&display->protocol_loggers)) {
|
||||||
message.resource = resource;
|
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);
|
wl_connection_copy(connection, p, sizeof p);
|
||||||
opcode = p[1] & 0xffff;
|
opcode = p[1] & 0xffff;
|
||||||
size = p[1] >> 16;
|
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)
|
if (len < size)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1168,10 +1192,23 @@ wl_display_create(void)
|
||||||
{
|
{
|
||||||
struct wl_display *display;
|
struct wl_display *display;
|
||||||
const char *debug;
|
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");
|
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;
|
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);
|
display = zalloc(sizeof *display);
|
||||||
if (display == NULL)
|
if (display == NULL)
|
||||||
|
|
@ -1794,6 +1831,24 @@ _wl_display_add_socket(struct wl_display *display, struct wl_socket *s)
|
||||||
return 0;
|
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_EXPORT const char *
|
||||||
wl_display_add_socket_auto(struct wl_display *display)
|
wl_display_add_socket_auto(struct wl_display *display)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,14 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
struct wl_object;
|
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
|
* Protocol message signature
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1695,6 +1695,75 @@ TEST(global_remove)
|
||||||
display_destroy(d);
|
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
|
static void
|
||||||
terminate_display(void *arg)
|
terminate_display(void *arg)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ tests_protocol_c = custom_target(
|
||||||
output: 'tests-protocol.c'
|
output: 'tests-protocol.c'
|
||||||
)
|
)
|
||||||
|
|
||||||
executable(
|
exec_fd_leak_checker = executable(
|
||||||
'exec-fd-leak-checker',
|
'exec-fd-leak-checker',
|
||||||
'exec-fd-leak-checker.c',
|
'exec-fd-leak-checker.c',
|
||||||
dependencies: test_runner_dep
|
dependencies: test_runner_dep
|
||||||
|
|
@ -96,78 +96,116 @@ if get_option('scanner')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
tests = {
|
tests = {
|
||||||
'array-test': [],
|
'array-test': {},
|
||||||
'client-test': [ wayland_server_protocol_h ],
|
'client-test': {
|
||||||
'display-test': [
|
'extra_sources': [ wayland_server_protocol_h ],
|
||||||
wayland_client_protocol_h,
|
},
|
||||||
wayland_server_protocol_h,
|
'display-test': {
|
||||||
tests_server_protocol_h,
|
'extra_sources': [
|
||||||
tests_client_protocol_c,
|
wayland_client_protocol_h,
|
||||||
tests_protocol_c,
|
wayland_server_protocol_h,
|
||||||
],
|
tests_server_protocol_h,
|
||||||
'connection-test': [
|
tests_client_protocol_c,
|
||||||
wayland_client_protocol_h,
|
tests_protocol_c,
|
||||||
wayland_server_protocol_h,
|
],
|
||||||
],
|
},
|
||||||
'event-loop-test': [ wayland_server_protocol_h ],
|
'connection-test': {
|
||||||
'fixed-test': [],
|
'extra_sources': [
|
||||||
'interface-test': [ wayland_client_protocol_h ],
|
wayland_client_protocol_h,
|
||||||
'list-test': [],
|
wayland_server_protocol_h,
|
||||||
'map-test': [],
|
],
|
||||||
'sanity-test' : [
|
},
|
||||||
wayland_client_protocol_h,
|
'event-loop-test': {
|
||||||
wayland_server_protocol_h,
|
'extra_sources': [ wayland_server_protocol_h ],
|
||||||
],
|
},
|
||||||
'socket-test': [
|
'fixed-test': {},
|
||||||
wayland_client_protocol_h,
|
'interface-test': {
|
||||||
wayland_server_protocol_h,
|
'extra_sources': [ wayland_client_protocol_h ],
|
||||||
],
|
},
|
||||||
'queue-test': [
|
'list-test': {},
|
||||||
wayland_client_protocol_h,
|
'map-test': {},
|
||||||
wayland_server_protocol_h,
|
'sanity-test' : {
|
||||||
],
|
'extra_sources': [
|
||||||
'signal-test': [ wayland_server_protocol_h ],
|
wayland_client_protocol_h,
|
||||||
'newsignal-test': [
|
wayland_server_protocol_h,
|
||||||
# wayland-server.c is needed here to access wl_priv_* functions
|
],
|
||||||
files('../src/wayland-server.c'),
|
'runtime_deps': [ exec_fd_leak_checker ],
|
||||||
wayland_server_protocol_h,
|
},
|
||||||
],
|
'socket-test': {
|
||||||
'resources-test': [ wayland_server_protocol_h ],
|
'extra_sources': [
|
||||||
'message-test': [
|
wayland_client_protocol_h,
|
||||||
wayland_client_protocol_h,
|
wayland_server_protocol_h,
|
||||||
wayland_server_protocol_h,
|
],
|
||||||
],
|
},
|
||||||
'compositor-introspection-test': [
|
'queue-test': {
|
||||||
wayland_client_protocol_h,
|
'extra_sources': [
|
||||||
wayland_server_protocol_h,
|
wayland_client_protocol_h,
|
||||||
],
|
wayland_server_protocol_h,
|
||||||
'protocol-logger-test': [
|
],
|
||||||
wayland_client_protocol_h,
|
},
|
||||||
wayland_server_protocol_h,
|
'signal-test': {
|
||||||
],
|
'extra_sources': [ wayland_server_protocol_h ],
|
||||||
'headers-test': [
|
},
|
||||||
wayland_client_protocol_h,
|
'newsignal-test': {
|
||||||
wayland_server_protocol_h,
|
'extra_sources': [
|
||||||
'headers-protocol-test.c',
|
# wayland-server.c is needed here to access wl_priv_* functions
|
||||||
wayland_client_protocol_core_h,
|
files('../src/wayland-server.c'),
|
||||||
wayland_server_protocol_core_h,
|
wayland_server_protocol_h,
|
||||||
'headers-protocol-core-test.c',
|
],
|
||||||
],
|
},
|
||||||
'os-wrappers-test': [],
|
'resources-test': {
|
||||||
'proxy-test': [
|
'extra_sources': [ wayland_server_protocol_h ],
|
||||||
wayland_client_protocol_h,
|
},
|
||||||
wayland_server_protocol_h,
|
'message-test': {
|
||||||
],
|
'extra_sources': [
|
||||||
'enum-validator-test': [],
|
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_sources = [ test_name + '.c' ] + test_extra_sources
|
||||||
test_deps = [test_runner_dep, epoll_dep]
|
test_deps = [test_runner_dep, epoll_dep]
|
||||||
bin = executable(test_name, test_sources, dependencies: test_deps)
|
bin = executable(test_name, test_sources, dependencies: test_deps)
|
||||||
test(
|
test(
|
||||||
test_name,
|
test_name,
|
||||||
bin,
|
bin,
|
||||||
|
depends: test_runtime_deps,
|
||||||
env: [
|
env: [
|
||||||
'TEST_SRC_DIR=@0@'.format(meson.current_source_dir()),
|
'TEST_SRC_DIR=@0@'.format(meson.current_source_dir()),
|
||||||
'TEST_BUILD_DIR=@0@'.format(meson.current_build_dir()),
|
'TEST_BUILD_DIR=@0@'.format(meson.current_build_dir()),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue