Compare commits

...

165 commits
1.22.0 ... main

Author SHA1 Message Date
Isaac Freund
d81525a235 client: add wl_display_dispatch_pending_single
As well as wl_display_dispatch_queue_pending_single.

The motivation is writing libwayland bindings for a dynamic language
with exceptions/non-local returns. Since it is invalid for a
wl_dispatcher_func_t callback provided to libwayland to not return,
there is no way to prevent dispatching of further events in the case of
an exception in the dynamic language event handler.

Furthermore, since creating/destroying Wayland objects in an event
handler affects the dispatching of subsequent events by libwayland,
it is not possible to collect Wayland events in a queue outside
libwayland and dispatch them one-by-one after
wl_display_dispatch_pending() returns.

Adding libwayland API to dispatch at most one pending event solves this
problem cleanly. The bindings can have libwayland dispatch a single
event, wait for wl_display_dispatch_pending_single() to return, run the
dynamic language event handler (which may longjmp away), and continue
the loop for as long as there are more events to dispatch.

References: https://codeberg.org/ifreund/janet-wayland
Signed-off-by: Isaac Freund <mail@isaacfreund.com>
2025-09-16 11:48:33 +03:00
Kyle Brenneman
4673ef7e9c connection: Add a thread ID to WAYLAND_DEBUG output.
If WAYLAND_DEBUG contains the token "thread_id", and gettid() is
available, then include the current thread ID in the output from
wl_closure_print.

If multiple threads are sending requests, then those requests can get
interleaved. That's usually fine, but for wl_surface requests and
commits, that can cause problems ranging from incorrect behavior to
protocol errors.

Being able to see which requests are sent by different threads would
make such problems much easier to diagnose.

Signed-off-by: Kyle Brenneman <kbrenneman@nvidia.com>
2025-09-15 14:45:53 +01:00
Kyle Brenneman
77730f10a0 connection: Add a function to parse WAYLAND_DEBUG tokens
Add a new function, wl_check_env_token, to scan for a token in a
comma-separated string.

Change wl_display_create in wayland-server.c and
wl_display_connect_to_fd in wayland-client.c to use that instead of a
simple substring search.

This means that WAYLAND_DEBUG will accept a value like "client,server"
but not "clientserver". But, this will make it easier to add other
tokens without worrying about overlap between them.

Signed-off-by: Kyle Brenneman <kbrenneman@nvidia.com>
2025-09-15 14:45:53 +01:00
YaoBing Xiao
264da6a92b cursor: Free theme when size check fails to avoid memory leak
Signed-off-by: YaoBing Xiao <xiaoyaobing@uniontech.com>
2025-08-03 11:36:34 +00:00
ykla
cd0d1543c0 ci: upgrade FreeBSD to 14.3
Signed-off-by: ykla yklaxds@gmail.com
2025-07-20 02:09:35 +00:00
ykla
90187031e6
ci: upgrade FreeBSD to 14.2
Signed-off-by: ykla <yklaxds@gmail.com>
2025-06-25 07:18:28 +08:00
Simon Ser
eecf3f7635 build: re-open main branch for regular development
Signed-off-by: Simon Ser <contact@emersion.fr>
2025-06-21 13:38:28 +02:00
Demi Marie Obenour
adf84614ca connection: Do not busy-loop if a message exceeds the buffer size
If the length of a message exceeds the maximum length of the buffer, the
buffer size will reach its maximum value and stay there forever, with no
message ever being successfully processed.  Since libwayland uses
level-triggered epoll, this will cause the compositor to loop forever
and consume CPU time.  In libwayland 1.22 and below, there was an
explicit check that caused messages exceeding 4096 bytes to result in an
EOVERFLOW error, preventing the loop.  However, this check was removed
between d074d52902 ("connection: Dynamically resize connection buffers").

To prevent this problem, always limit the size of messages to 4096 bytes.
Since the default and minimum buffer size is 4096 bytes, this ensures
that a single message will always fit in the buffer.  It would be
possible to allow larger messages if the buffer size was larger, but the
maximum size of a message should not depend on the buffer size chosen by
the compositor.

Rejecting messages that exceed 4092 bytes seems to have the advantage of
reserving 4 bits, not 3, in the size field for future use.  However,
message sizes in the range [0x0, 0x7] are invalid, so one can obtain a
fourth bit by negating the meaning of bit 12 if bits 0 through 11
(inclusive) are 0.  Allowing 4096-byte messages provides the far more
important advantage that regressions compared to 1.22 are impossible
and regressions compared to 1.23 are extremely unlikely.  The only case
where a regression is possible is:

- The receiving side is using libwayland 1.23.
- The sending side is either using libwayland 1.23 or is not using
  libwayland.
- The sender sends a message exceeding 4096 bytes.
- If the sender of the large message is the client, the server has
  increased the buffer size from the default value.

This combination is considered extremely unlikely, as libwayland 1.22
and below would disconnect upon receiving such a large message.
4096-byte messages, however, have always worked, so there was no reason
to avoid sending them.

Fixes: d074d52902 ("connection: Dynamically resize connection buffers").
Fixes: #494
Signed-off-by: Demi Marie Obenour <demi@invisiblethingslab.com>
2025-06-21 11:29:04 +00:00
Pekka Paalanen
ba9f9a446f doc: add a section on color management
I think the docbook deserves an introduction to how color management is
designed in Wayland, aimed at people who are familiar with pixels but
new to the topic.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2025-06-12 14:37:32 +03:00
Matt Turner
53fbc2b0c1 egl: Make wayland-egl symbols check depend on wayland_egl
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/515
Signed-off-by: Matt Turner <mattst88@gmail.com>
2025-06-08 17:30:55 +00:00
Matt Turner
fdac631d17 tests: Depend on exec-fd-leak-checker
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/514
Signed-off-by: Matt Turner <mattst88@gmail.com>
2025-06-08 17:30:55 +00:00
Matt Turner
6c1da92018 tests: Add support for specifying runtime dependencies
Signed-off-by: Matt Turner <mattst88@gmail.com>
2025-06-08 17:30:55 +00:00
Matt Turner
ca83185e8a tests: Make tests dict elements dicts themselves
Previously each value was a list of extra sources. The next commit will add an
additional field to each test, so they need to be dicts themselves.

Signed-off-by: Matt Turner <mattst88@gmail.com>
2025-06-08 17:30:55 +00:00
Manuel Stoeckl
4a0c4e2119 doc: Further explain typical display socket lookup
This change mentions the case where WAYLAND_SOCKET is used, which helps
people avoid just testing 'getenv(WAYLAND_DISPLAY)' to see if a
Wayland compositor is available;

Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
2025-06-08 16:20:35 +00:00
Manuel Stoeckl
387adc6a79 server: Document wl_display_add_socket_auto
The exact sequence of names tried has de facto become part of the API.

Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
2025-06-08 16:20:35 +00:00
Tobias Stoeckmann
0de833da29 cursor: Properly check realloc for errors
Do not override realloc's input pointer before checking for errors,
otherwise it's not possible to keep old value, as intended.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-08 16:16:09 +00:00
Tobias Stoeckmann
2978fd701a cursor: Ignore invalid cursor files
The header offset must not be smaller than file header length.
Ignore such invalid files.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-08 16:16:09 +00:00
Tobias Stoeckmann
5c2f31d8d6 cursor: Gracefully handle huge cursor files
If cursor files require more than INT_MAX bytes, it is possible to
trigger out of boundary writes.

Since these sizes are most likely not desired anyway, gracefully
handle these situations like out of memory errors.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-08 16:16:09 +00:00
Tobias Stoeckmann
ce0ac4f29e cursor: Gracefully handle out of memory condition
If the full path could not be constructed, avoid calling opendir(NULL)
which, depending on library, might trigger undefined behavior.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-08 16:16:09 +00:00
Tobias Stoeckmann
1bee7aa4a7 cursor: Fix undefined behavior with huge names
If an index.theme contains a theme name which gets close to INT_MAX,
then creation of full path can lead to a signed integer overflow,
which is undefined behavior.

Fix this by turning one of the values to size_t. Easy solution for a
probably never occurring issue.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-08 16:16:09 +00:00
Kirill Primak
6281ccbd3d client: fix conversion specifier in the discarded event log message
Signed-off-by: Kirill Primak <vyivel@eclair.cafe>
2025-06-01 14:56:34 +03:00
Caitlyn
ecff0ee10c debug: Colorize output for easier reading
Signed-off-by: Caitlyn <caitlynrosestewart@gmail.com>
2025-06-01 11:21:36 +00:00
Caitlyn Stewart
827d0c30ad connection: fix segfault in wl_closure_invoke()
Signed-off-by: Caitlyn Stewart <caitlynrosestewart@gmail.com>
2025-05-27 14:45:32 +01:00
Simon Ser
62cd0990e8 build: bump version to 1.23.90 for the RC1 release
Signed-off-by: Simon Ser <contact@emersion.fr>
2025-05-22 21:00:30 +02:00
Simon Ser
9b169ff945 protocol: drop reference to linux-explicit-synchronization
This protocol has been superseded. Replace this outdated reference
with a generic hint that protocol extensions may provide this
functionality.

Signed-off-by: Simon Ser <contact@emersion.fr>
2025-05-20 20:57:52 +00:00
Tobias Stoeckmann
cc06c3825f Fix typos
Typos found with codespell and during code audit.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-20 20:49:32 +00:00
Isaac Freund
8cad6f7b82 server: add wl_resource_get_interface()
This is useful for the wayland bindings/scanner I'm working on for a
dynamically typed language.

Signed-off-by: Isaac Freund <mail@isaacfreund.com>
2025-05-20 20:31:16 +00:00
Isaac Freund
4497232102 client: add wl_proxy_get_interface()
This is useful for the wayland bindings/scanner I'm working on for a
dynamically typed language.

Signed-off-by: Isaac Freund <mail@isaacfreund.com>
2025-05-20 20:31:16 +00:00
David Edmundson
3214f858e2 protocol: Clarify sending of wl_seat.capabilities
It wasn't explicitly stated that wl_seat.capabilities should also
be sent on bind. Everyone did because it was obviously sensible.

This also clarifies that static seat name should be sent before
announcing capabilities so clients can associate these devices with the
right seat name.

Signed-off-by: David Edmundson <davidedmundson@kde.org>
2025-05-20 20:20:13 +00:00
Simon Ser
66fc3f007d shm: linkify function references in docs
Parentheses make it so the generated HTML documentation contains
links, which makes navigation easier.

Signed-off-by: Simon Ser <contact@emersion.fr>
2025-05-20 20:14:52 +00:00
Simon Ser
9dd1b2d7e3 shm: fix comment about wl_shm_buffer_begin_access() safety
The paragraph later says that accessing different buffers is
allowed. The function checks whether the same pool is accessed.

Signed-off-by: Simon Ser <contact@emersion.fr>
2025-05-20 20:14:52 +00:00
Sebastian Wick
d2a3d33063 shm: Generate an error when shm access failed even without a resource
Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-05-20 21:50:22 +02:00
Sebastian Wick
9367c4da76 shm: Add wl_shm_buffer ref and unref functions
Shared memory buffers are currently tied to the lifetime of their
underlying wl_buffer resource. This becomes problematic when the client
destroys the resource after committing new state which references the
wl_buffer because a compositor might have to defer applying the commit.

This commit adds methods to keep the wl_shm_buffer alive longer than the
underlying resource. This implicitly also keeps the buffer pool alive
and because the wl_shm_buffer uses offsets into the pool, it even works
when the underlying storage gets remapped somewhere else, which can
happen when the client resizes the pool.

Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-05-20 21:50:22 +02:00
Sebastian Wick
af453f876e shm: Remove refcount check which cannot be triggered
If the pool refcount reaches zero, it is freed, so accessing its members
is UB which ASan would catch.

Also simplify check for negative refcounts.

Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-05-20 21:50:09 +02:00
Sebastian Wick
9ec01ab2dc shm: Linkify wl_shm_pool_unref in the ref_pool documentation
Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-05-20 21:30:56 +02:00
Michel Dänzer
6137c8c213 protocol: Clarify wl_buffer.release description
Sebastian pointed out that the existing text could be read as
wl_buffer.destroy not being allowed before the wl_buffer.release event
arrives, contrary to what the wl_surface.attach description says.
Clarify to be consistent with the latter.

This is a follow-up for
https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/141 .

Signed-off-by: Michel Dänzer <mdaenzer@redhat.com>

v2:
* Simplify clarification, don't talk about callbacks. (Julian Orth)
* Add reference to details in the description of wl_surface.attach.
  (Daniel Stone)
v3:
* Tweak clarification again. (Sebastian Wick)
v4:
* Make clarification even less ambiguous. (Simon Ser, Julian Orth)
v5:
* Just refer to the description of wl_surface.attach instead of trying
  to clarify anything here. (Sebastian Wick)
2025-03-15 23:12:07 +00:00
Julian Orth
7033e74857 client: document get_listener behavior for dispatchers
This seems to have been the case since 2013.

This is useful for wrappers that need two pointers to identify proxies.
One pointer (stored in the user data) pointing to a singleton object to
identify that the proxy has a known structure. And one pointer (stored
in the dispatcher data) pointing to per-proxy data.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
2025-03-15 23:07:39 +00:00
Simon Ser
dbfa8d784e scanner: use separate guards for validator functions
Generated XXX_is_valid() functions for enums are guarded behind the
same #define as the enum itself. This worked fine until recently,
but since fbd7460737 ("scanner: add new enum-header mode") we're
also generating enum-only headers.

When including the enum-only header first, and then the server
header, the validator functions are missing.

Define a separate guard to fix this.

Signed-off-by: Simon Ser <contact@emersion.fr>
2025-02-23 23:38:15 +01:00
Vlad Zahorodnii
1ab6b693b1 Forward declarate timespec struct
The `timespec` struct is defined in `time.h` header but only if
`_POSIX_C_SOURCE` is set or when using the C11 standard.

Signed-off-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
2025-02-06 10:18:17 +00:00
David Redondo
afd498b6f5 Also use [[deprecated]] when compiling with at least C++14
Signed-off-by: David Redondo <kde@david-redondo.de>
2025-02-05 09:43:21 +01:00
David Redondo
7c2ffb0d71 Make wayland-util.h -Wundef safe when compiled by a C++ compiler
Fixes #522
Signed-off-by: David Redondo <kde@david-redondo.de>
2025-02-05 09:21:43 +01:00
Daniel Stone
02ad102e2d build: Add -lm to pkg-config dependencies
Now that wl_fixed_from_double() calls round() from a function declared
in a header, our users need to explicitly pick that dependency up in
order to avoid build errors.

Signed-off-by: Daniel Stone <daniels@collabora.com>
Closes: wayland/weston#991
2025-02-05 06:52:53 +00:00
Sebastian Wick
74f322c35a tests: Add dispatch timeout tests
Add tests which verify that...

* wl_display_dispatch_timeout with a big enough timeout behaves the same
  as wl_display_dispatch
* wl_display_dispatch_timeout will time out when there are no messages
  to dispatch

Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-02-04 14:09:51 +00:00
Sebastian Wick
00dcf6b323 client: Add wl_display_dispatch_timeout
A variant of wl_display_dispatch_queue_timeout for the default queue.

Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-02-04 14:09:51 +00:00
Sebastian Wick
ddd348da7e client: Add wl_display_dispatch_queue_timeout
For dispatching messages on a queue with a timeout.

This slightly changes the samantics of wl_display_dispatch. Previously
it was possible for it to return even though there wasn't a single
dispatched event. The function correctly returned 0 in this case but it
is now used to indicate a timeout.

Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-02-04 14:09:51 +00:00
Sebastian Wick
ff8b885523 event-loop: Use timespec utils instead of hand-rolling our own
Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-02-04 14:09:51 +00:00
Sebastian Wick
893e4fc46d timespec: Implement saturating timespec substraction
Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-02-04 14:09:51 +00:00
Sebastian Wick
9d5de6062b timespec: Pull in timespec_after and timespec_add from mesa
Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-02-04 14:09:51 +00:00
Sebastian Wick
37469d5ced timespec: Pull in timespec.h from weston
Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-02-04 14:09:51 +00:00
Sebastian Wick
bdba21ec92 server: add const qualifier to function arguments where possible
Makes it possible to e.g. `call wl_client_get_credentials` with a `const
struct wl_client *` from a global filter callback.

Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2025-01-22 14:28:50 +00:00
Daniel Stone
597a6b94f5 ci: Update ci-templates
This includes an explicit way to specify the container architecture,
which fixes our rebuilds on ARMv7.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2025-01-21 16:43:45 +00:00
Haihua Hu
f246e619d1 util: reduce error of wl_fixed_from_double()
when cast double to fixed pointer, there will be big
error, eg 1919.9998 to 1919. Call round before cast
to get nearest value 1920 of 1919.9998

Signed-off-by: Haihua Hu <jared.hu@nxp.com>
2025-01-09 09:58:32 +09:00
Demi Marie Obenour
9cb3d7aa9d connection: Fix wrong format string
Prevents undefined behavior if there is not enough space in the buffer
for a queued message.

Signed-off-by: Demi Marie Obenour <demi@invisiblethingslab.com>
2024-11-30 16:02:55 -05:00
Demi Marie Obenour
290c36bc50 tests: Avoid calling function with wrong type
Calling a function with the wrong type is immediate undefined behavior,
even if the ABI says it should be harmless.  UBSAN picks it up
immediately, and any decent control-flow integrity mechanism will as
well.

Signed-off-by: Demi Marie Obenour <demi@invisiblethingslab.com>
2024-11-30 11:31:36 -05:00
Demi Marie Obenour
4273a5edc8 connection: Avoid undefined pointer arithmetic
Creating a pointer that is more than one element past the end of an
array is undefined behavior, even if the pointer is not dereferenced.
Avoid this undefined behavior by using `p >= end` instead of
`p + 1 > end` and `SOMETHING > end - p` instead of
`p + SOMETHING > end`.

Signed-off-by: Demi Marie Obenour <demi@invisiblethingslab.com>
2024-11-29 19:19:45 -05:00
Julian Orth
10df74c240 protocol: add wl_fixes interface
This commit describes a new wl_fixes interface that can be used to
destroy wl_registry objects.

Users of libwayland-client should use it as follows:

- call wl_fixes_destroy_registry(registry)
- call wl_registry_destroy(registry)

Users of libwayland-server should, in their implementation of the
request, call wl_resource_destroy(registry).

It should be similar in other protocol implementations.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
2024-11-18 09:25:20 +00:00
YaoBing Xiao
f67db75ec1 cursor: add check to ensure wl_shm_create_pool succeeded
Signed-off-by: YaoBing Xiao <xiaoyaobing@uniontech.com>
2024-10-18 16:49:45 +08:00
Simon Ser
38f91fe6ad protocol: document that wl_surface.offset is role-specific
This request doesn't make sense for all surface roles. For instance,
for maximized/tiled/fullscreen xdg_toplevel, for xdg_popup, for
layer-shell surfaces, etc.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-10-05 14:06:51 +00:00
Andri Yngvason
1b0d45e9c6 Add wl_keyboard key repeat events
This allows the compositor to take over the responsibility of repeating
keys.

Signed-off-by: Andri Yngvason <andri@yngvason.is>
2024-09-23 15:23:45 +00:00
Julian Orth
7c6259e9ad protocol: clients should not emulate key-press events on enter
The previous change introducing the logical state caused some confusion.
Clarify that most application should not use the list of pressed keys.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
2024-09-10 07:36:48 +00:00
Demi Marie Obenour
6c4a695045 connection: Reject strings containing NUL bytes
libwayland cannot construct these messages as it uses strlen() to
determine string lengths.  libwayland is also guaranteed to misinterpret
these messages, since message handlers only get a pointer and no length.
Therefore, reject strings containing NUL bytes.

Also remove a redundant check from the unmarshalling code.  The
zero-length case has already been checked for.

Signed-off-by: Demi Marie Obenour <demi@invisiblethingslab.com>
2024-08-18 17:08:56 +00:00
Joaquim Monteiro
0239b082b9
meson: Fix use of install_data() without specifying install_dir
This was broken (when in a subproject) before Meson 1.3.0, and so
Meson warns against this unless the project targets 1.3.0 or newer.

Signed-off-by: Joaquim Monteiro <joaquim.monteiro@protonmail.com>
2024-08-15 14:13:57 +01:00
Fangzhou Ge
5b692b50b9 client: Log the object and methods when marshalling or sending fails
The log that appears before a display_error can be captured as crash
signature. Useful to know what it is.

This is cherry-picked from chromium https://crrev.com/c/4697877

Signed-off-by: Fangzhou Ge <fangzhoug@chromium.org>
2024-08-12 15:49:14 -04:00
Simon Ser
efa648056a ci: use detached MR pipelines
See the freedesktop wiki [1]. This allows external contributors to
have CI run properly.

[1]: https://gitlab.freedesktop.org/freedesktop/freedesktop/-/wikis/GitLab-CI#for-project-developers

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-08-09 20:46:58 +00:00
Derek Foreman
58bb6c7211 src: Finish assert() clean-up
From cleanup commit 0cecde304:
assert()s can be compiled away by #defining NDEBUG. Some build systems
do this. Using wl_abort gives a human readable error message and it
isn't compiled away.

That commit missed one final assert, presumably due to missing it with
grep because of a coding style issue. Fix that up, and remove inclusion
of <assert.h> as appropriate.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2024-08-09 20:38:52 +00:00
Sebastian Wick
2bbd80c8df doc: Require strings to be UTF-8
Nothing checks this yet but this gives us the opportunity to do so when
we want.

Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2024-08-09 20:33:05 +00:00
Kirill Primak
65454cf7db server: expose wl_resource_post_error_vargs()
Signed-off-by: Kirill Primak <vyivel@eclair.cafe>
2024-08-09 20:29:24 +00:00
Kirill Primak
64248963d3 server: add wl_resource_post_error() docs
Signed-off-by: Kirill Primak <vyivel@eclair.cafe>
2024-08-09 20:29:24 +00:00
Kirill Primak
a6a4e081da Put WL_DEPRECATED in front of the function declarations
This fixes the following clang error when using C23:

../src/wayland-server-core.h:680:41: error: 'deprecated' attribute cannot be applied to types
  680 |                      int32_t stride, uint32_t format) WL_DEPRECATED;
      |                                                       ^
../src/wayland-util.h:52:25: note: expanded from macro 'WL_DEPRECATED'
   52 | #define WL_DEPRECATED [[deprecated]]
      |                         ^

Signed-off-by: Kirill Primak <vyivel@eclair.cafe>
2024-08-09 20:25:11 +00:00
Sebastian Wick
f6f0a3cdec client: Handle proxies with no queue
wl_proxy_get_queue can return NULL if the queue of the proxy was already
destroyed with wl_event_queue_destroy. In this case, the queue also has
no name anymore.

Fixes: b42218f ("client: Allow setting names for queues")
Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2024-07-26 18:33:28 +02:00
meltq
0cecde304f src: switch asserts to wl_abort
assert()s can be compiled away by #defining NDEBUG. Some build systems
do this. Using wl_abort gives a human readable error message and it
isn't compiled away. This commit closes issue #230.

Signed-off-by: meltq <tejasvipin76@gmail.com>
2024-07-11 17:44:04 +00:00
Simon Ser
fa1811ce3e tests: add enum bitfield test
Signed-off-by: Simon Ser <contact@emersion.fr>
2024-07-09 18:22:10 +02:00
Simon Ser
c669d99259 scanner: fix validator for bitfields
Bitfields are valid if the value only contains bits inside of
the supported entries for the given version.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-07-09 18:22:10 +02:00
Simon Ser
caaa308c0d scanner: extract validator function emission to helper function
This function will grow in the next commit.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-07-09 18:22:10 +02:00
Simon Ser
1d5772b7b9 build: re-open main branch for regular development
Signed-off-by: Simon Ser <contact@emersion.fr>
2024-05-30 21:07:24 +02:00
Simon Ser
a156431ea6 build: bump to version 1.23.0 for the official release
Signed-off-by: Simon Ser <contact@emersion.fr>
2024-05-30 20:59:51 +02:00
Hugo Osvaldo Barrera
26c419e046 protocol: clarify divergence in compositor behaviour
This is intended to only document the current situation. Whether further
behaviour will be defined is out of scope and left for protocol v7.

See: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/363
Signed-off-by: Hugo Osvaldo Barrera <hugo@whynothugo.nl>
2024-05-29 14:23:38 +02:00
Simon Ser
0b1626f473 build: bump to version 1.22.93 for the RC1 release
Signed-off-by: Simon Ser <contact@emersion.fr>
2024-05-23 18:12:41 +02:00
Simon Ser
4bade62938 server: document wl_display_add_socket_fd() ownership
wl_socket_destroy() will close the socket.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-05-22 08:55:03 +00:00
Vlad Zahorodnii
17965d99e8 server: Clarify fd ownership in wl_client_create()
It's unclear whether one needs to call close() if wl_client_create()
fails. Hopefully this change makes it more clear.

Signed-off-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
2024-05-16 12:57:42 +03:00
Simon Ser
f870320958 build: bump to version 1.22.92 for the beta release
Signed-off-by: Simon Ser <contact@emersion.fr>
2024-05-09 16:50:40 +02:00
Julian Orth
9e4f256927 protocol: explicitly describe wl_keyboard state
And the allowed state transitions.

There has been some confusion regarding which state transitions are
allowed. This change should clarify this.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
2024-05-09 14:43:19 +00:00
Simon Ser
6963320218 build: bump to version 1.22.91 for the alpha release
Signed-off-by: Simon Ser <contact@emersion.fr>
2024-04-25 17:46:07 +02:00
Derek Foreman
e60c631ff2 client: print debug events that have no listener
Currently WAYLAND_DEBUG text ignores events that have no listener.

It can be helpful to know when you're receiving unhandled events,
as you may have forgotten to add a listener, or adding a dispatch
may have magically seemed to fix code that doesn't appear to be
dispatching anything.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2024-04-24 16:40:18 +00:00
Sebastian Wick
9069af78a7 protocol: define content updates and their internal queue
Multiple protocols use the term content update without a fill
definition. It makes sense to define it in the core protocol so that not
every other protocol has to define it.

This is supposed to retain the current semantics and only changes the
documentation while defining new terms.

Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2024-04-24 16:32:06 +00:00
Simon Ser
6e1db53916 client: fix invalid doc command for WL_MARSHAL_FLAG_DESTROY
Fixes the following warning:

    src/wayland-client-core.h:125: warning: Found non-existing group 'wl_proxy' for the command '@ingroup', ignoring command

"\memberof" cannot be used here because it only works on functions.
The docs for "\memberof" say that "\relates" works in a similar way.

While at it, use a "\" command instead of a "@" command for
consistency with the rest of the file.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-04-24 16:27:50 +00:00
Simon Ser
80c65f862f tests: add deprecated-since attributes
Add a new event and enum entry to small.xml with a deprecated-since
attribute to exercise the scanner code generation.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-04-24 16:18:28 +00:00
Simon Ser
da8e1bbc45 protocol: mark wl_pointer.axis_discrete as deprecated
Since version 8, this event isn't sent anymore.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-04-24 16:18:28 +00:00
Simon Ser
ee12e69b8f Add support for the deprecated-since XML attribute
This marks a request, event or enum entry as deprecated since a
given version.

Note that it's not clear what it means if an entry is deprecated
at some version, and the enum is used from some completely different
interface than where it was defined. However, that's a more general
issue with enums, see:
https://gitlab.freedesktop.org/wayland/wayland/-/issues/435

Signed-off-by: Simon Ser <contact@emersion.fr>
References: https://gitlab.freedesktop.org/wayland/wayland/-/issues/89
2024-04-24 16:18:28 +00:00
Chloé Vulquin
16aee2ec38 xcursor: catch theme inheritance loops
As of currently, when an xcursor theme depends on itself or another theme
that will eventually depend on it, `xcursor_load_theme` will recurse
infinitely while processing the inherits.

This change introduces a stack-allocated linked list of visited nodes
by name, and skips any already visited nodes in the inherit list.

Side effects:
* Since the linked list is stack-allocated, there is a potential for an
  overflow if there is a very long list of dependencies. If this turns out
  to be a legitimate concern, the linked list is trivial to convert to
  being heap-allocated.
* There is an existing linked list (technically doubly linked list)
  implementation in the wayland codebase. As of currently, the xcursor
  codebase does not refer to it. Consequently, this change writes a
  minimal single linked list implementation to utilize directly.

This changeset fixes #317.

Signed-off-by: Chloé Vulquin <toast@bunkerlabs.net>
2024-04-24 12:28:38 +02:00
Simon Ser
b258d5f361 scanner: add validators for enums
Right now compositors need to manually check that enum values sent
by the client are valid. In particular:

- Check that the value sent by the client is not outside of the enum.
- Check that the version of the enum entry is consistent with the
  object version.

Automatically generate validator functions to perform these tasks.

Signed-off-by: Simon Ser <contact@emersion.fr>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/104
2024-04-23 09:17:02 +00:00
Julian Orth
5eeaac6e11 Clarify behavior of buffer transformations
The new text describes how

- Mutter
- Plasma
- Sway 1.8
- Jay

behave.

Sway 1.9 flipped the behavior of 90 degree and 270 degree
set_buffer_transform requests. [mpv] also changed the behavior of its
vo_wayland_dmabuf backend which makes it only work correctly on sway
1.9.

[mpv]: https://github.com/mpv-player/mpv/pull/12509

It seems that the previous text was open to interpretation or at least
caused some amount of confusion.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
2024-04-23 09:08:09 +00:00
Colin Kinloch
af1dc3ef4b protocol: Undefine wl_display_sync callback data
Signed-off-by: Colin Kinloch <colin.kinloch@collabora.com>
2024-04-23 08:43:44 +00:00
6t8k
03e304544b
cursor: memfd_create: try MFD_NOEXEC_SEAL
Effective from Linux 6.3 onward, this creates the memfd without execute
permissions and prevents that setting from ever being changed. A
run-time fallback is made to not using MFD_NOEXEC_SEAL when a
libwayland-cursor compiled on Linux >= 6.3 is run on Linux < 6.3.

This is a defense-in-depth security measure and silences a respective
kernel warning; see: https://lwn.net/Articles/918106/

This implementation is adopted from dnkl's `foot` terminal emulator.

Signed-off-by: 6t8k <6t8k@noreply.codeberg.org>
2024-04-21 19:17:46 +02:00
Simon Ser
c5d145a602 ci: turn on -Dwerror=true for FreeBSD
It was turned on for Linux only.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-04-09 00:48:18 +00:00
Simon Ser
37699a98b1 ci: use --fatal-meson-warnings
Turns Meson warnings into errors. Useful to avoid missing warnings.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-04-09 00:48:18 +00:00
Simon Ser
e7df1f2af2 build: bump minimum Meson version to 0.57
Fixes the following warning:

    tests/meson.build:91: WARNING: Project targets '>= 0.56.0' but uses feature introduced in '0.57.0': env arg in run_target.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-04-09 00:48:18 +00:00
Simon Ser
ad4ed17335 ci: bump Meson version to 0.57
Signed-off-by: Simon Ser <contact@emersion.fr>
2024-04-09 00:48:18 +00:00
Manuel Stoeckl
d074d52902 connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.

This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.

To avoid the issue, resize the connection buffers dynamically when they
get full.

Both data and fd buffers are resized on demand.

The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.

The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.

v0: Manuel:
   Dynamically resize connection buffers - Both data and fd buffers are
   resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
   (yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
   client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
   the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
   ring-buffer has space remaining (or can be expanded),
   wl_connection_queue() should store the message rather than
   returning an error.
4. When the receive ring-buffer is at capacity but more data is
   available to be read, wl_connection_read() should attempt to
   expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
   Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
    by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)

Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2024-04-08 14:05:32 +00:00
Simon Ser
36cef8653f util: convert macros to inline functions
Functionally equivalent except the usual macro footguns are avoided
and type safety is increased.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-03-28 17:56:34 +01:00
Isaac Freund
4945f2664f wl_touch.cancel: document lack of frame event
This appears to be what at least wlroots-based compositors and kwin do
in practice. However, it's not abundantly clear from the protocol text
what the expected behavior here is. This patch fixes that.

Signed-off-by: Isaac Freund <mail@isaacfreund.com>
2024-03-28 13:27:54 +00:00
Simon Ser
2e0dbb7021 tests: add scanner test for enum-header
Signed-off-by: Simon Ser <contact@emersion.fr>
2024-03-28 13:21:28 +00:00
Simon Ser
fbd7460737 scanner: add new enum-header mode
This generates a header with only enum definitions. This is useful
to share enum headers between libraries and library users.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-03-28 13:21:28 +00:00
Jordan Williams
2621484037 egl: Disable symbols check for static builds
The symbols check only works for dynamic libraries.
When building statically, the test fails.
This is caused by the check filtering out non-dynamic symbols with nm.
This change skips the check when building only static libraries.

Signed-off-by: Jordan Williams <jordan@jwillikers.com>
2024-03-28 13:13:47 +00:00
David Benjamin
8a7ecd774c util: fix undefined behavior in wl_array_for_each
If a wl_array has size zero, wl_array_for_each computes NULL + 0 to get
to the end pointer. This should be fine, and indeed it would be fine in
C++. But the C specification has a mistake here and it is actually
undefined behavior. See
https://davidben.net/2024/01/15/empty-slices.html

Clang's -fsanitize=undefined flags this. I ran into this in Chromium's
build with wayland-scanner on one of our XML files.

../../third_party/wayland/src/src/scanner.c:1853:2: runtime error: applying zero offset to null pointer
    #0 0x55c979b8e02c in emit_code third_party/wayland/src/src/scanner.c:1853:2
    #1 0x55c979b89323 in main third_party/wayland/src/src/scanner.c
    #2 0x7f8dfdb8c6c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #3 0x7f8dfdb8c784 in __libc_start_main csu/../csu/libc-start.c:360:3
    #4 0x55c979b70f39 in _start (...)

An empty XML file is sufficient to hit this case, so I've added it as a
test. To reproduce, undo the fix and include only the test, then build
with:

  CC=clang CFLAGS="-fno-sanitize-recover=undefined" meson build/ -Db_sanitize=undefined -Db_lundef=false
  ninja -C build test

Signed-off-by: David Benjamin <davidben@google.com>
2024-03-24 20:00:01 -04:00
Simon Ser
aa2a6d560b protocol: document that color channels provide electrical values
Expand the work done in [1] to document that all channels store
electrical values. See the discussion in [2].

[1]: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/316
[2]: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/250#note_2311377

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-03-12 13:04:51 +00:00
Simon Ser
44b1c0c737 connection: use enum wl_arg_type in wl_message_count_arrays()
Missed it in 155dd63b58 ("Introduce enum wl_arg_type").

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-03-06 19:09:35 +01:00
Simon Ser
440defbd2b client: simplify create_proxies() loop
Decrease the indentation a bit. No functional change.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-03-06 14:18:37 +01:00
Simon Ser
7a1e7dd549 client: simplify create_outgoing_proxy() loop
Decrease the indentation a bit. No functional change.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-03-06 14:18:18 +01:00
Simon Ser
830883e5b2 connection: simplify wl_closure_lookup_objects() loop
Decrease the indentation a bit. No functional change.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-03-06 14:18:18 +01:00
Simon Ser
155dd63b58 Introduce enum wl_arg_type
This is less cryptic to read than letters, and allows the compiler
to check switch statements exhaustiveness.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-03-06 14:17:48 +01:00
Thomas Lukaszewicz
47de87263c Mitigate UAF crashes due to wl_client_destroy reentrancy
There are situations in which a call into wl_client_destroy() can
result in a reentrant call into wl_client_destroy() - which
results in UAF / double free crashes.

For example, this can occur in the following scenario.

1. Server receives a message notifying it that a client has
   disconnected (WL_EVENT_HANGUP [1])

2. This beings client destruction with a call to wl_client_destroy()

3. wl_client_destroy() kicks off callbacks as client-associated
   resources are cleaned up and their destructors and destruction
   signals are invoked.

4. These callbacks eventually lead to an explicit call to
   wl_display_flush_clients() as the server attempts to flush
   events to other connected clients.

5. Since the client has already begun destruction, when it is
   reached in the iteration the flush fails wl_client_destroy()
   is called again [2].

This patch guards against this reentrant condition by removing
the client from the display's client list when wl_client_destroy()
is first called. This prevents access / iteration over the client
after wl_client_destroy() is called.

In the example above, wl_display_flush_clients() will pass over
the client currently undergoing destruction and the reentrant
call is avoided.

[1] 8f499bf404/src/wayland-server.c (L342)

[2] 8f499bf404/src/wayland-server.c (L1512)

Signed-off-by: Thomas Lukaszewicz [thomaslukaszewicz@gmail.com](mailto:thomaslukaszewicz@gmail.com)
2024-02-23 00:40:32 +00:00
Sébastien Marie
d80bce5f1a build: fix build and provide compat for OpenBSD
- wayland-egl-abi-check: try to use llvm-nm first instead of BSD nm (incompatible options)
- avoid forcing _POSIX_C_SOURCE=200809L (SOCK_CLOEXEC become available)
- epoll(7) is provided by a userspace wrapper around kqueue(2) as FreeBSD
- when using SO_PEERCRED, the struct to use is `struct sockpeercred` instead of `struct ucred` on OpenBSD
- provide a compatibility layer for count_open_fds() using sysctl(2) as FreeBSD

Signed-off-by: Sebastien Marie <semarie@online.fr>
2024-02-21 15:46:41 +00:00
Sébastien Marie
791912c678 compat: prefer waitpid() over waitid()
while both are defined by POSIX, waitpid() is more common than waitid().

Signed-off-by: Sebastien Marie <semarie@online.fr>
2024-02-21 15:46:41 +00:00
Simon Ser
a74aa93394 protocol: mention wl_surface events from wl_output.{scale,transform}
The wl_output events should not be used anymore for guessing the
preferred scale and transform of a surface. We have explicit events
for that now.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-02-21 09:14:23 +00:00
Sebastian Wick
9c4213ed3e server: add wl_client_get_user_data/wl_client_set_user_data
The only way to attach some data to a wl_client seems to be setting up a
destroy listener and use wl_container_of. Let's make it straight forward
to attach some data.

Having an explicit destroy callback for the user data makes managing the
user data lifetime much more convenient. All other callbacks, be they
wl_resource request listeners, destroy listeners or destructors, or
wl_client destroy listeners, can assume that the wl_client user data
still exists if it was set. Otherwise making that guarantee would be
complicated.

Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
2024-02-15 10:53:21 +00:00
Kirill Primak
6a7284c632 event-loop: use wl_priv_signal for the destroy signal
Signed-off-by: Kirill Primak <vyivel@eclair.cafe>
2024-02-08 17:18:28 +00:00
Thomas Lukaszewicz
d275bc7f84 Mitigate UAF crashes due to iteration over freed wl_resources
Currently it is possible to iterate over client-owned resources
during client destruction that have had their associated memory
released.

This can occur when client code calls wl_client_destroy(). The
following sequence illustrates how this may occur.

 1. The server initiates destruction of the connected client via
    call to wl_client_destroy().

 2. Resource destroy listeners / destructors are invoked and
    resource memory is freed one resource at a time [1].

 3. If a listener / destructor for a resource results in a call
    to wl_client_for_each_resource(), the iteration will proceed
    over resources that have been previously freed in step 2,
    resulting in UAFs / crashes.

The issue is that resources remain in the client's object map
even after they have had their memory freed, and are removed
from the map only after each individual resource has had its
memory released.

This patch corrects this by ensuring resource destruction first
invokes listeners / destructors and then removing them from the
client's object map before releasing the associated memory.

[1] https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/src/wayland-server.c?ref_type=heads#L928

Signed-off-by: Thomas Lukaszewicz thomaslukaszewicz@gmail.com
2024-02-07 09:45:41 +00:00
Kirill Primak
8f499bf404 protocol: clarify pending wl_buffer destruction
This matches the current behavior of KWin, Mutter, and Weston.

References: https://gitlab.freedesktop.org/wayland/wayland/-/issues/387
Signed-off-by: Kirill Primak <vyivel@eclair.cafe>
2024-01-27 15:17:28 +00:00
Mikhail Gusarov
88ece8a44d doc: Improve wording for packed IDs
"is incompatible with the implementation in libwayland" is a common
source of confusion as evidenced by repeated discussions in IRC
channel.

Improve the wording by making clear that
- packing IDs is a protocol requirement
- there are implementations (including libwayland) that enforce it

Signed-off-by: Mikhail Gusarov <dottedmag@dottedmag.net>
2024-01-22 12:37:26 +00:00
Derek Foreman
b42218f790 client: Allow setting names for queues
Allow setting a name for an event queue. The queue is used only for
printing additional debug information.

Debug output can now show the name of the event queue an event is
dispatched from, or the event queue of a proxy when a request is made.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2024-01-22 12:34:14 +00:00
Erik Chen
2f17d480e8 connection: Spruce up logging for client errors.
Some code paths that lead to a client error and connection termination
have no associated logging, or insufficient logging. This makes it
difficult to understand what went wrong. This commit adds or supplements
logging for all these code paths.

Signed-off-by: Erik Chen <erikchen@chromium.org>
2024-01-19 15:51:33 +00:00
John Lindgren
9867bdb111 connection: Small simplification to wl_connection_write()
wl_connection_write() contained an exact copy of the logic in
wl_connection_queue().  Simplify things by just calling
wl_connection_queue() from wl_connection_write().

Signed-off-by: John Lindgren <john@jlindgren.net>
2024-01-19 15:25:54 +00:00
Andreas Cord-Landwehr
8c49ee3112 Consider pkgconfig sysroot for pkgdatadir
For libs/cflags this is done automatically, but not for manually accessed
variables. This matches what wayland-protocols does.

Signed-off-by: Andreas Cord-Landwehr <cordlandwehr@kde.org>
2024-01-19 15:18:23 +00:00
Simon Ser
fd42f70baf shm: implement version 2
This version adds a release request.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-01-19 15:12:29 +00:00
Simon Ser
f06736a8a0 protocol: add wl_shm.release request
Allows clients to cleanly release wl_shm objects. Useful for clients
using multiple wl_registry objects (e.g. via libraries).

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-01-19 15:12:29 +00:00
Simon Ser
9e233e31a2 shm: fix resource versions
This was hardcoded to 1 regardless of the version passed to the
callback or the version of the parent resource.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-01-19 15:12:29 +00:00
Ben Widawsky
8072ab0a50 protocol: clarify scale expecations
Since the positivity of zero is debatable, and, in some cases scale was simply
underspecified, clarify the situation.

Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
2024-01-19 14:35:06 +00:00
Simon Ser
647398ead4 util: use C23 deprecated attribute
Signed-off-by: Simon Ser <contact@emersion.fr>
2024-01-19 14:21:59 +00:00
Simon Ser
56b9c92b98 util: use C23 typeof if available
Instead of using the non-standard __typeof__, prefer the standard
typeof operator introduced in C23.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-01-19 14:21:59 +00:00
Simon Ser
dc1da181db protocol: document wl_surface.offset for sub-surfaces
Document that the request is ignored, since this is the behavior
of most compositors.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-01-19 14:14:15 +00:00
Consolatis
6daa1b8713 cursor: add aliases for cursor name spec
The cursor name spec [1] describes how cursors should be named,
and is widely used. Add aliases so that users can pass these
names to libwayland-cursor without having to add fallbacks for
X11 cursor names.

[1]: https://www.freedesktop.org/wiki/Specifications/cursor-spec/

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-01-19 14:08:16 +00:00
Simon Ser
0e139cfbc7 build: add a gen-scanner-test target
This adds a command to re-generate the test data. This needs to be
done when either an XML source file or the scanner's output is
changed.

Signed-off-by: Simon Ser <contact@emersion.fr>
2024-01-15 14:29:10 +01:00
Julian Orth
6626d4d98c protocol: wl_subsurface will never be focused
The spec does not describe which actions cause the compositor to assign
keyboard focus to a surface, leaving this up to the compositor.
Compositors differ in their behavior when the user clicks on a
sub-surface. Some will move the keyboard focus to the subsurface whereas
others will only ever assign the keyboard focus to toplevel surfaces.
Some applications (e.g. firefox) seem to require the second behavior.

This patch specifies that sub-surfaces never get the keyboard focus.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
2023-12-27 18:02:07 +00:00
Francesco Guastella
86588fbdeb build: define tests in egl/meson.build when the 'tests' option is enabled
Signed-off-by: Francesco Guastella <guastella.francesco@gmail.com>
2023-12-10 14:58:04 +00:00
Kirill Primak
82d8b21827 protocol: improve wl_subsurface.{set_position,place_above} description
Don't mention when the parent surface state is applied; the parent
surface isn't necessarily a sub-surface.

Signed-off-by: Kirill Primak <vyivel@eclair.cafe>
2023-11-21 15:54:58 +00:00
Kirill Chibisov
8a19dc19a1 protocol: clarify defaults with wl_compositor@v6
This should be sufficient for clients to not decide to fallback to
output based logic to determine scaling/transform when compositor
doesn't send any of the v6 events.

Signed-off-by: Kirill Chibisov <contact@kchibisov.com>
2023-11-21 15:50:11 +00:00
Simon Ser
2a91f01d6c util: simplify wl_fixed_from_double()
Same as 0e0ae7e290 ("util: simplify wl_fixed_to_double()"), but
for the reverse function.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-11-21 15:47:13 +00:00
Simon Ser
3007718b0c gitlab: make issue template the default
The issue template is hard to notice because it's not the default.
Users have to explicitly select it from the easy-to-miss dropdown
to get the warning.

Make the template the default one, so that new users are less likely
to miss it.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-11-21 15:44:31 +00:00
Simon Ser
e4eb42d073 protocol: refer to wl_surface.offset in wl_data_device.start_drag
Passing an offset to wl_surface.attach is not supported in the
latest version of the interface.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-11-21 15:36:00 +00:00
David Benjamin
50ea9c5b1c connection: avoid calling memcpy on NULL, 0
Due to what is arguably a mistake in the C language specification,
passing NULL to memcpy and friends is undefined behavior (UB) even when
the count is 0. C additionally mistakenly leaves NULL + 0 and NULL -
NULL undefined. (C++ fixes this mistake.) These are very problematic
because (NULL, 0) is a natural representation of the empty slice.

Some details:
https://github.com/llvm/llvm-project/issues/49459
https://www.imperialviolet.org/2016/06/26/nonnull.html

Unfortunately, despite how clearly this is a mistake, glibc headers and
GCC now try to exploit this specification mistake and will miscompile
code, so C projects need to workaround this. In particular, UBSan from
Clang will flag this as a bug (although Clang itself has the good sense
to never lean on this bug). We've run into a few UBSan errors in
Chromium stemming from Wayland's memcpy calls. Add runtime guards as
needed to avoid these cases.

Note: Chromium's copy of wayland has
https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/188
applied. It is possible the ring_buffer_copy UB cases are only reachable
with that MR applied, I'm not sure. But it seemed simplest to just add
the fix to wayland as-is. Then when/if that MR lands, it will pick this
up.

Signed-off-by: David Benjamin <davidben@google.com>
2023-11-08 08:41:16 -05:00
David Edmundson
edb943dc64 client: Add method to get display for a given proxy
This can be useful for additional validation purposes when handling
proxies. This is similar to existing server side API
wl_global_get_display.

Signed-off-by: David Edmundson <david@davidedmundson.co.uk>
2023-08-07 13:38:01 +00:00
Simon Ser
379a6f6759 ci: upgrade FreeBSD to 13.2
Signed-off-by: Simon Ser <contact@emersion.fr>
2023-08-02 16:47:07 +02:00
Simon Ser
63b0050561 ci: upgrade Debian to bookworm
This is the current Debian stable release.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-08-02 16:47:07 +02:00
Simon Ser
a81f947aff ci: upgrade ci-templates
Newer ci-templates contains bugfixes.

While at it, stop using a GitLab YAML reference, because we only
use this value in one spot.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-08-02 16:47:07 +02:00
Simon Ser
7b27881cd1 cursor: check return value of snprintf()
Fixes a new warning in GCC 7:

    FAILED: cursor/libwayland-cursor.so.0.22.90.p/xcursor.c.o
    cc -Icursor/libwayland-cursor.so.0.22.90.p -Icursor -I../cursor -I. -I.. -Isrc -I../src -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Werror -std=c99 -O3 -D_POSIX_C_SOURCE=200809L -Wno-unused-parameter -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden -fPIC '-DICONDIR="/usr/share/X11/icons"' -MD -MQ cursor/libwayland-cursor.so.0.22.90.p/xcursor.c.o -MF cursor/libwayland-cursor.so.0.22.90.p/xcursor.c.o.d -o cursor/libwayland-cursor.so.0.22.90.p/xcursor.c.o -c ../cursor/xcursor.c
    ../cursor/xcursor.c: In function 'xcursor_load_theme':
    ../cursor/xcursor.c:596:39: error: '%s' directive output between 7 and 7 bytes may cause result to exceed 'INT_MAX' [-Werror=format-truncation=]
      596 |         snprintf(full, full_size, "%s/%s/%s", dir, subdir, file);
          |                                       ^~
    ......
      764 |                 full = xcursor_build_fullname(dir, "cursors", "");
          |                                                    ~~~~~~~~~
    ../cursor/xcursor.c:596:41: error: '/' directive output between 1 and 1 bytes may cause result to exceed 'INT_MAX' [-Werror=format-truncation=]
      596 |         snprintf(full, full_size, "%s/%s/%s", dir, subdir, file);
          |                                         ^
    cc1: all warnings being treated as errors

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-08-02 16:47:07 +02:00
Simon Ser
72da004b3e protocol: fix whitespace
This file uses tabs instead of 8 spaces.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-07-19 11:01:17 +00:00
Peter Hutterer
e3908eb360 Add a triage-policies file for bugbot
With a default template for the common case of "this is not a protocol bug".

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-07-07 21:18:08 +10:00
Alex Yang
6d33346571 debug: Replace "@<id>" with "#<id>" in logs
Wayland debug logs resemble email addresses. This is a problem when
anonymizing logs from users. For example:

[2512874.343] xdg_surface@700.configure(333)

In the above log line, the substring "surface@700.config" can be
mistaken for an email address and redacted during anonymization.

Signed-off-by: Alex Yang <aycyang@google.com>
2023-06-27 14:08:25 -07:00
Simon Ser
4ec379ebcc tests: manually wrap libc functions
The way we're wrapping libc functions via dlsym() is pretty fragile
and breaks on FreeBSD. The failures happen in our CI and are pretty
random, see e.g. [1].

Use a more manual way to wrap via a function pointer.

[1]: https://gitlab.freedesktop.org/wayland/wayland/-/jobs/44204010

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-06-27 13:31:50 +02:00
Simon Ser
4a7348e48c egl: add missing ABI check test
We were building the executable for the test, but not declaring
the test.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-06-20 09:20:49 +02:00
Simon Ser
f181de1bcf tests: add missing proxy-test
This was probably lost during a rebase.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-06-20 09:20:49 +02:00
Simon Ser
56dfdb7614 server: use bool in struct fields
Use bool instead of int for boolean values, to make it more
explicit what the field contains. For instance "error" is not to
be confused with an error code.

This is all private API.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-05-30 09:18:34 +00:00
Simon Ser
a3c499493b protocol: refer to wl_surface.offset in set_cursor
The offset in wl_surface.attach has been superseded by
wl_surface.offset. Refer to the new request instead of using the
deprecated one.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-05-23 09:33:43 +00:00
Sebastian Wick
f3026c916e protocol: specify the exact form of premultiplication
There are two ways to do pre-multiplication of the alpha channel into
the color channels: on optical values or on electrical values. While
pre-multiplication with optical values is arguably more correct, because
operations like blending or scaling require pre-multiplied, optical
color channels, wayland and compositors by default work with
pre-multiplied electrical values. This is most likely a convention that
Wayland took from Cairo.

This commit makes sure that the expectation of pre-multiplied electrical
values is properly documented.

Signed-off-by: Sebastian Wick <sebastian.wick@redhat.com>
2023-05-09 14:52:58 +02:00
Simon Ser
2aec19ce41 build: override wayland-scanner dep
This allows a parent project to find wayland-scanner.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-05-09 09:56:18 +00:00
Simon Ser
8f2a33cffc server: stop wl_display_run() on dispatch error
If wl_event_loop_dispatch() fails, we could enter an infinite loop,
repeatedly calling a failing wl_event_loop_dispatch() forever.

Signed-off-by: Simon Ser <contact@emersion.fr>
2023-05-09 09:50:53 +00:00
Simon Ser
0e0ae7e290 util: simplify wl_fixed_to_double()
We can just use a simple division instead of bit operations with
magic numbers. Readability matters more than performance here.

References: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/296
Signed-off-by: Simon Ser <contact@emersion.fr>
2023-05-09 09:33:06 +00:00
Yang Wang
11b17c1286 event-loop: optimize timer check logic
the 'has_timers' flag can be returned directly without having to track all the ready events
when a timer is found ready.

Signed-off-by: Yang Wang <KevinYang.Wang@amd.com>
2023-05-03 19:21:17 +00:00
Manuel Stoeckl
b1b97e8d34 tests: drop misleading fixed-benchmark
Because this benchmark performed wl_fixed_to_double conversions
on a long sequence of consecutive integers, the compiler could
optimize away the addition performed in wl_fixed_to_double, merging
it with the loop iteration code. This made tests/fixed-benchmark.c
significantly underestimate the actual cost of the current
wl_fixed_to_double implementation.

Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
2023-05-03 19:15:12 +00:00
Manuel Stoeckl
d40052e083 protocol: add new shm formats
This brings the format list up to date with libdrm 2.4.115.

Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
2023-05-03 19:10:32 +00:00
Joshua Ashton
3bac2e5fb8 event-loop: Handle EINTR and EAGAIN in wl_event_loop_dispatch
This fixes an issue where it was not possible to start Gamescope under GDB on some setups.
https://github.com/ValveSoftware/gamescope/issues/743

Any signals would cause epoll_wait to return -1 and set errno to EINTR.

This also handles the EAGAIN case like the other polling loops in libwayland.

Signed-off-by: Joshua Ashton <joshua@froggi.es>
2023-05-02 12:36:35 +01:00
Xaver Hugl
1e259a255a protocol: improve wl_keyboard focus documentation
The compositor must not send any key events while a surface is not focused,
but in order to allow for common actions like ctrl+scroll for zooming to work
with unfocused surfaces it may do so with modifiers.

Signed-off-by: Xaver Hugl <xaver.hugl@gmail.com>
2023-04-12 13:37:51 +00:00
Simon Ser
307b23626d protocol: disallow re-using wl_data_source
As pointed out in [1], re-using a wl_data_source for multiple start_drag or
set_selection requests has bad consequences, because this object has events
that allo tracking the state of a selection/drag-and-drop operation. Tracking
two operations at the same time isn't possible with this interface.

[1]: https://lists.freedesktop.org/archives/wayland-devel/2019-January/039936.html

Signed-off-by: Simon Ser <contact@emersion.fr>
Signed-off-by: Daniel Stone <daniels@collabora.com>
2023-04-04 11:39:08 +00:00
Simon Ser
cdd890a6f8 build: re-open main branch for regular development 2023-04-04 13:38:18 +02:00
64 changed files with 5444 additions and 900 deletions

View file

@ -37,15 +37,13 @@
# - documentation at https://freedesktop.pages.freedesktop.org/ci-templates/
# - repo at https://gitlab.freedesktop.org/freedesktop/ci-templates/
# Here we use a fixed ref in order to isolate ourselves from ci-templates
# 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.
.templates_sha: &template_sha d5aa3941aa03c2f716595116354fb81eb8012acb # see https://docs.gitlab.com/ee/ci/yaml/#includefile
include:
- project: 'freedesktop/ci-templates'
ref: *template_sha
# Here we use a fixed ref in order to isolate ourselves from ci-templates
# 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: 48c2c583a865bd59be21e8938df247faf460099c
file:
- '/templates/debian.yml'
- '/templates/freebsd.yml'
@ -64,6 +62,13 @@ stages:
- "Build and test"
- "Other build configurations"
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
.ci-rules:
rules:
- when: on_success
@ -72,12 +77,12 @@ stages:
.os-debian:
variables:
BUILD_OS: debian
FDO_DISTRIBUTION_VERSION: bullseye
FDO_DISTRIBUTION_VERSION: bookworm
FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build'
FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.56.0'
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: "2022-08-08.0"
FDO_DISTRIBUTION_TAG: "2025-01-21.1"
.debian-x86_64:
extends:
@ -96,6 +101,7 @@ stages:
- .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.
@ -149,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.
@ -219,7 +224,7 @@ armv7-debian-container_prep:
stage: "Build and test"
script:
- cd "$BUILDDIR"
- meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons -Dwerror=true ${MESON_BUILD_TYPE} ..
- meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons --fatal-meson-warnings -Dwerror=true ${MESON_BUILD_TYPE} ..
- ninja -k0 -j${FDO_CI_CONCURRENT:-4}
- meson test --num-processes ${FDO_CI_CONCURRENT:-4}
- ninja clean
@ -301,14 +306,14 @@ armv7-release-debian-build:
.os-freebsd:
variables:
BUILD_OS: freebsd
FDO_DISTRIBUTION_VERSION: "13.1"
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: "2022-09-08.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: "-Ddocumentation=false"
MESON_ARGS: "--fatal-meson-warnings -Dwerror=true -Ddocumentation=false"
.freebsd-x86_64:
extends:

View file

@ -4,5 +4,5 @@ library only. Issues with Wayland during day-to-day usage are almost
certainly a bug in your compositor and **not** a bug with in this
repository.
Please remove this comment before filing your bug.
Please remove this comment before filing your issue.
-->

33
.triage-policies.yml Normal file
View file

@ -0,0 +1,33 @@
# This is a set of bugbot commands for issues and merge requests - setting any of the
# bugbot::foo labels will trigger gitlab-triage to run with this ruleset (well, the
# one we have on the main branch at the time)
#
# Note that for adding labels, the label must first created in the project.
resource_rules:
issues:
rules:
- name: "Close bugs that aren't Wayland bugs"
conditions:
labels:
- "bugbot::not-wayland"
actions:
remove_labels:
- "bugbot::not-wayland"
comment: |
Thank you for the report, but your issue does not look like it would belong here. Sorry.
This repository is for the Wayland protocol specification and the
low-level C library that deals with the protocol.
This issue here is a bug not with the protocol itself but with either
- your compositor or desktop environment's implementation of the Wayland protocol and surrounding functionality,
- the individual application that triggers this issue, or
- the kernel driver used by your hardware
Please file the issue against your compositor/desktop environment, the application
or the kernel drivers instead, whichever seems more likely to you. If you are not sure,
file an issue against the application.
status: "close"
merge_requests:
rules:
[]

View file

@ -29,7 +29,6 @@
* http://fontforge.org/pcf-format.html
*/
#include <assert.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>

View file

@ -551,4 +551,19 @@ static struct cursor_metadata {
{ "xterm", 9, 16, 4, 8, 2400 },
{ "hand1", 13, 16, 12, 0, 2544 },
{ "watch", 16, 16, 15, 9, 2752 },
/* https://www.freedesktop.org/wiki/Specifications/cursor-spec/ */
{ "sw-resize", 16, 16, 1, 14, 0 },
{ "se-resize", 16, 16, 14, 14, 256 },
{ "s-resize", 15, 16, 7, 14, 512 },
{ "all-scroll", 16, 16, 8, 8, 752 },
{ "default", 10, 16, 1, 1, 1008 },
{ "w-resize", 16, 15, 1, 7, 1168 },
{ "e-resize", 16, 15, 14, 7, 1408 },
{ "nw-resize", 16, 16, 1, 1, 1648 },
{ "ne-resize", 16, 16, 14, 1, 1904 },
{ "n-resize", 15, 16, 7, 1, 2160 },
{ "text", 9, 16, 4, 8, 2400 },
{ "pointer", 13, 16, 12, 0, 2544 },
{ "wait", 16, 16, 15, 9, 2752 },
};

View file

@ -40,6 +40,11 @@
#include <sys/mman.h>
#endif
/* Fallback to no flag when missing the definition */
#ifndef MFD_NOEXEC_SEAL
#define MFD_NOEXEC_SEAL 0
#endif
#include "os-compatibility.h"
#ifndef HAVE_MKOSTEMP
@ -124,7 +129,21 @@ os_create_anonymous_file(off_t size)
int fd;
#ifdef HAVE_MEMFD_CREATE
fd = memfd_create("wayland-cursor", MFD_CLOEXEC | MFD_ALLOW_SEALING);
/*
* Linux kernels older than 6.3 reject MFD_NOEXEC_SEAL with EINVAL.
* Try first *with* it, and if that fails, try again *without* it.
*/
errno = 0;
fd = memfd_create(
"wayland-cursor",
MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL);
if (fd < 0 && errno == EINVAL && MFD_NOEXEC_SEAL != 0) {
fd = memfd_create(
"wayland-cursor",
MFD_CLOEXEC | MFD_ALLOW_SEALING);
}
if (fd >= 0) {
/* We can add this seal before calling posix_fallocate(), as
* the file is currently zero-sized anyway.

View file

@ -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;
}

View file

@ -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;
@ -585,6 +587,7 @@ xcursor_build_fullname(const char *dir, const char *subdir, const char *file)
{
char *full;
size_t full_size;
int ret;
if (!dir || !subdir || !file)
return NULL;
@ -593,7 +596,11 @@ xcursor_build_fullname(const char *dir, const char *subdir, const char *file)
full = malloc(full_size);
if (!full)
return NULL;
snprintf(full, full_size, "%s/%s/%s", dir, subdir, file);
ret = snprintf(full, full_size, "%s/%s/%s", dir, subdir, file);
if (ret < 0) {
free(full);
return NULL;
}
return full;
}
@ -681,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;
@ -721,38 +732,45 @@ load_all_cursors_from_dir(const char *path, int size,
closedir(dir);
}
/** Load all the cursor 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
* 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
* struct xcursor_images objects passed to the callback with
* xcursor_images_destroy().
*
* \param theme The name of theme that should be loaded
* \param size The desired size of the cursor images
* \param load_callback A callback function that will be called
* for each cursor loaded. The first parameter is the struct xcursor_images
* object representing the loaded cursor and the second is a pointer
* to data provided by the user.
* \param user_data The data that should be passed to the load callback
*/
void
xcursor_load_theme(const char *theme, int size,
struct xcursor_nodelist {
size_t nodelen;
const char *node;
struct xcursor_nodelist *next;
};
static bool
nodelist_contains(struct xcursor_nodelist *nodelist, const char *s, size_t ss)
{
struct xcursor_nodelist *vi;
for (vi = nodelist; vi && vi->node; vi = vi->next) {
if (vi->nodelen == ss && !strncmp(s, vi->node, vi->nodelen))
return true;
}
return false;
}
static void
xcursor_load_theme_protected(const char *theme, int size,
void (*load_callback)(struct xcursor_images *, void *),
void *user_data)
void *user_data,
struct xcursor_nodelist *visited_nodes)
{
char *full, *dir;
char *inherits = NULL;
const char *path, *i;
char *xcursor_path;
size_t si;
struct xcursor_nodelist current_node;
if (!theme)
theme = "default";
current_node.next = visited_nodes;
current_node.node = theme;
current_node.nodelen = strlen(theme);
visited_nodes = &current_node;
xcursor_path = xcursor_library_path();
for (path = xcursor_path;
path;
@ -775,9 +793,44 @@ xcursor_load_theme(const char *theme, int size,
free(dir);
}
for (i = inherits; i; i = xcursor_next_path(i))
xcursor_load_theme(i, size, load_callback, user_data);
for (i = inherits; i; i = xcursor_next_path(i)) {
si = strlen(i);
if (nodelist_contains(visited_nodes, i, si))
continue;
xcursor_load_theme_protected(i, size, load_callback, user_data, visited_nodes);
}
free(inherits);
free(xcursor_path);
}
/** 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 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
* 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().
*
* \param theme The name of theme that should be loaded
* \param size The desired size of the cursor images
* \param load_callback A callback function that will be called
* for each cursor loaded. The first parameter is the struct xcursor_images
* object representing the loaded cursor and the second is a pointer
* to data provided by the user.
* \param user_data The data that should be passed to the load callback
*/
void
xcursor_load_theme(const char *theme, int size,
void (*load_callback)(struct xcursor_images *, void *),
void *user_data)
{
xcursor_load_theme_protected(theme,
size,
load_callback,
user_data,
NULL);
}

View 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>

View file

@ -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>

View file

@ -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
@ -150,9 +152,10 @@
<listitem>
<para>
Starts with an unsigned 32-bit length (including null terminator),
followed by the string contents, including terminating null byte,
then padding to a 32-bit boundary. A null value is represented
with a length of 0.
followed by the UTF-8 encoded string contents, including
terminating null byte, then padding to a 32-bit boundary. A null
value is represented with a length of 0. Interior null bytes are
not permitted.
</para>
</listitem>
</varlistentry>
@ -312,9 +315,10 @@
reserved to represent a null or non-existent object.
For efficiency purposes, the IDs are densely packed in the sense that
the ID N will not be used until N-1 has been used. Any ID allocation
algorithm that does not maintain this property is incompatible with
the implementation in libwayland.
the ID N will not be used until N-1 has been used. This ordering is
not merely a guideline, but a strict requirement, and there are
implementations of the protocol that rigorously enforce this rule,
including the ubiquitous libwayland.
</para>
</section>
<section id="sect-Protocol-Compositor">

View file

@ -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"/>

View file

@ -54,6 +54,7 @@ publican_sources = [
'Protocol.xml',
'Xwayland.xml',
'Compositors.xml',
'Color.xml',
'Client.xml',
'Server.xml'
]

View file

@ -9,18 +9,27 @@ wayland_egl = library(
install: true
)
executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c')
if get_option('tests')
wayland_egl_abi_check = executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c')
test('wayland-egl abi check', wayland_egl_abi_check)
nm_path = find_program('nm').full_path()
test(
'wayland-egl symbols check',
find_program('wayland-egl-symbols-check'),
env: [
'WAYLAND_EGL_LIB=@0@'.format(wayland_egl.full_path()),
'NM=@0@'.format(nm_path)
]
)
if get_option('default_library') != 'static'
nm_path = find_program(['llvm-nm', 'nm']).full_path()
wayland_egl_shared = wayland_egl
if get_option('default_library') == 'both'
wayland_egl_shared = wayland_egl.get_shared_lib()
endif
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)
]
)
endif
endif
install_headers([
'wayland-egl.h',

View file

@ -1,8 +1,8 @@
project(
'wayland', 'c',
version: '1.22.0',
version: '1.24.90',
license: 'MIT',
meson_version: '>= 0.56.0',
meson_version: '>= 0.57.0',
default_options: [
'warning_level=2',
'buildtype=debugoptimized',
@ -16,7 +16,7 @@ config_h.set_quoted('PACKAGE', meson.project_name())
config_h.set_quoted('PACKAGE_VERSION', meson.project_version())
cc_args = []
if host_machine.system() != 'freebsd'
if host_machine.system() not in ['freebsd', 'openbsd']
cc_args += ['-D_POSIX_C_SOURCE=200809L']
endif
add_project_arguments(cc_args, language: 'c')
@ -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))
@ -69,7 +70,7 @@ endif
config_h.set10('HAVE_BROKEN_MSG_CMSG_CLOEXEC', have_broken_msg_cmsg_cloexec)
if get_option('libraries')
if host_machine.system() == 'freebsd'
if host_machine.system() in ['freebsd', 'openbsd']
# When building for FreeBSD, epoll(7) is provided by a userspace
# wrapper around kqueue(2).
epoll_dep = dependency('epoll-shim')
@ -131,7 +132,9 @@ if get_option('scanner')
'wayland-scanner.mk',
'protocol/wayland.xml',
'protocol/wayland.dtd',
])
],
install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'wayland'),
)
install_data(
[ 'wayland-scanner.m4' ],

View file

@ -8,10 +8,12 @@
<!ATTLIST request name CDATA #REQUIRED>
<!ATTLIST request type CDATA #IMPLIED>
<!ATTLIST request since CDATA #IMPLIED>
<!ATTLIST request deprecated-since CDATA #IMPLIED>
<!ELEMENT event (description?,arg*)>
<!ATTLIST event name CDATA #REQUIRED>
<!ATTLIST event type CDATA #IMPLIED>
<!ATTLIST event since CDATA #IMPLIED>
<!ATTLIST event deprecated-since CDATA #IMPLIED>
<!ELEMENT enum (description?,entry*)>
<!ATTLIST enum name CDATA #REQUIRED>
<!ATTLIST enum since CDATA #IMPLIED>
@ -21,6 +23,7 @@
<!ATTLIST entry value CDATA #REQUIRED>
<!ATTLIST entry summary CDATA #IMPLIED>
<!ATTLIST entry since CDATA #IMPLIED>
<!ATTLIST entry deprecated-since CDATA #IMPLIED>
<!ELEMENT arg (description?)>
<!ATTLIST arg name CDATA #REQUIRED>
<!ATTLIST arg type CDATA #REQUIRED>

View file

@ -46,7 +46,7 @@
compositor after the callback is fired and as such the client must not
attempt to use it after that point.
The callback_data passed in the callback is the event serial.
The callback_data passed in the callback is undefined and should be ignored.
</description>
<arg name="callback" type="new_id" interface="wl_callback"
summary="callback object for the sync request"/>
@ -212,7 +212,7 @@
</request>
</interface>
<interface name="wl_shm_pool" version="1">
<interface name="wl_shm_pool" version="2">
<description summary="a shared memory pool">
The wl_shm_pool object encapsulates a piece of memory shared
between the compositor and client. Through the wl_shm_pool
@ -262,17 +262,17 @@
created, but using the new size. This request can only be
used to make the pool bigger.
This request only changes the amount of bytes that are mmapped
by the server and does not touch the file corresponding to the
file descriptor passed at creation time. It is the client's
responsibility to ensure that the file is at least as big as
the new pool size.
This request only changes the amount of bytes that are mmapped
by the server and does not touch the file corresponding to the
file descriptor passed at creation time. It is the client's
responsibility to ensure that the file is at least as big as
the new pool size.
</description>
<arg name="size" type="int" summary="new size of the pool, in bytes"/>
</request>
</interface>
<interface name="wl_shm" version="1">
<interface name="wl_shm" version="2">
<description summary="shared memory support">
A singleton global object that provides support for shared
memory.
@ -419,6 +419,21 @@
<entry name="xbgr16161616" value="0x38344258" summary="[63:0] x:B:G:R 16:16:16:16 little endian"/>
<entry name="argb16161616" value="0x38345241" summary="[63:0] A:R:G:B 16:16:16:16 little endian"/>
<entry name="abgr16161616" value="0x38344241" summary="[63:0] A:B:G:R 16:16:16:16 little endian"/>
<entry name="c1" value="0x20203143" summary="[7:0] C0:C1:C2:C3:C4:C5:C6:C7 1:1:1:1:1:1:1:1 eight pixels/byte"/>
<entry name="c2" value="0x20203243" summary="[7:0] C0:C1:C2:C3 2:2:2:2 four pixels/byte"/>
<entry name="c4" value="0x20203443" summary="[7:0] C0:C1 4:4 two pixels/byte"/>
<entry name="d1" value="0x20203144" summary="[7:0] D0:D1:D2:D3:D4:D5:D6:D7 1:1:1:1:1:1:1:1 eight pixels/byte"/>
<entry name="d2" value="0x20203244" summary="[7:0] D0:D1:D2:D3 2:2:2:2 four pixels/byte"/>
<entry name="d4" value="0x20203444" summary="[7:0] D0:D1 4:4 two pixels/byte"/>
<entry name="d8" value="0x20203844" summary="[7:0] D"/>
<entry name="r1" value="0x20203152" summary="[7:0] R0:R1:R2:R3:R4:R5:R6:R7 1:1:1:1:1:1:1:1 eight pixels/byte"/>
<entry name="r2" value="0x20203252" summary="[7:0] R0:R1:R2:R3 2:2:2:2 four pixels/byte"/>
<entry name="r4" value="0x20203452" summary="[7:0] R0:R1 4:4 two pixels/byte"/>
<entry name="r10" value="0x20303152" summary="[15:0] x:R 6:10 little endian"/>
<entry name="r12" value="0x20323152" summary="[15:0] x:R 4:12 little endian"/>
<entry name="avuy8888" value="0x59555641" summary="[31:0] A:Cr:Cb:Y 8:8:8:8 little endian"/>
<entry name="xvuy8888" value="0x59555658" summary="[31:0] X:Cr:Cb:Y 8:8:8:8 little endian"/>
<entry name="p030" value="0x30333050" summary="2x2 subsampled Cr:Cb plane 10 bits per channel packed"/>
</enum>
<request name="create_pool">
@ -442,6 +457,17 @@
</description>
<arg name="format" type="uint" enum="format" summary="buffer pixel format"/>
</event>
<!-- Version 2 additions -->
<request name="release" type="destructor" since="2">
<description summary="release the shm object">
Using this request a client can tell the server that it is not going to
use the shm object anymore.
Objects created via this interface remain unaffected.
</description>
</request>
</interface>
<interface name="wl_buffer" version="1">
@ -453,9 +479,11 @@
client provides and updates the contents is defined by the buffer factory
interface.
If the buffer uses a format that has an alpha channel, the alpha channel
is assumed to be premultiplied in the color channels unless otherwise
specified.
Color channels are assumed to be electrical rather than optical (in other
words, encoded with a transfer function) unless otherwise specified. If
the buffer uses a format that has an alpha channel, the alpha channel is
assumed to be premultiplied into the electrical color channel values
(after transfer function encoding) unless otherwise specified.
Note, because wl_buffer objects are created from multiple independent
factory interfaces, the wl_buffer interface is frozen at version 1.
@ -473,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
@ -847,6 +877,7 @@
<enum name="error">
<entry name="role" value="0" summary="given wl_surface has another role"/>
<entry name="used_source" value="1" summary="source has already been used"/>
</enum>
<request name="start_drag">
@ -868,7 +899,7 @@
The icon surface is an optional (can be NULL) surface that
provides an icon to be moved around with the cursor. Initially,
the top-left corner of the icon surface is placed at the cursor
hotspot, but subsequent wl_surface.attach request can move the
hotspot, but subsequent wl_surface.offset requests can move the
relative position. Attach requests must be confirmed with
wl_surface.commit as usual. The icon surface is given the role of
a drag-and-drop icon. If the icon surface already has another role,
@ -876,6 +907,10 @@
The input region is ignored for wl_surfaces with the role of a
drag-and-drop icon.
The given source may not be used in any further set_selection or
start_drag requests. Attempting to reuse a previously-used source
may send a used_source error.
</description>
<arg name="source" type="object" interface="wl_data_source" allow-null="true" summary="data source for the eventual transfer"/>
<arg name="origin" type="object" interface="wl_surface" summary="surface where the drag originates"/>
@ -889,6 +924,10 @@
to the data from the source on behalf of the client.
To unset the selection, set the source to NULL.
The given source may not be used in any further set_selection or
start_drag requests. Attempting to reuse a previously-used source
may send a used_source error.
</description>
<arg name="source" type="object" interface="wl_data_source" allow-null="true" summary="data source for the selection"/>
<arg name="serial" type="uint" summary="serial number of the event that triggered this request"/>
@ -1411,7 +1450,7 @@
<entry name="invalid_size" value="2" summary="buffer size is invalid"/>
<entry name="invalid_offset" value="3" summary="buffer offset is invalid"/>
<entry name="defunct_role_object" value="4"
summary="surface was destroyed before its role object"/>
summary="surface was destroyed before its role object"/>
</enum>
<request name="destroy" type="destructor">
@ -1440,9 +1479,9 @@
When the bound wl_surface version is 5 or higher, passing any
non-zero x or y is a protocol violation, and will result in an
'invalid_offset' error being raised. The x and y arguments are ignored
and do not change the pending state. To achieve equivalent semantics,
use wl_surface.offset.
'invalid_offset' error being raised. The x and y arguments are ignored
and do not change the pending state. To achieve equivalent semantics,
use wl_surface.offset.
Surface contents are double-buffered state, see wl_surface.commit.
@ -1467,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
@ -1479,6 +1519,13 @@
If wl_surface.attach is sent with a NULL wl_buffer, the
following wl_surface.commit will remove the surface content.
If a pending wl_buffer has been destroyed, the result is not specified.
Many compositors are known to remove the surface content on the following
wl_surface.commit, but this behaviour is not universal. Clients seeking to
maximise compatibility should not destroy pending buffers and should
ensure that they explicitly remove content from surfaces, even after
destroying buffers.
</description>
<arg name="buffer" type="object" interface="wl_buffer" allow-null="true"
summary="buffer of surface contents"/>
@ -1618,16 +1665,18 @@
<description summary="commit pending surface state">
Surface state (input, opaque, and damage regions, attached buffers,
etc.) is double-buffered. Protocol requests modify the pending state,
as opposed to the current state in use by the compositor. A commit
request atomically applies all pending state, replacing the current
state. After commit, the new pending state is as documented for each
related request.
as opposed to the active state in use by the compositor.
On commit, a pending wl_buffer is applied first, and all other state
second. This means that all coordinates in double-buffered state are
relative to the new wl_buffer coming into use, except for
wl_surface.attach itself. If there is no pending wl_buffer, the
coordinates are relative to the current surface contents.
A commit request atomically creates a content update from the pending
state, even if the pending state has not been touched. The content
update is placed in a queue until it becomes active. After commit, the
new pending state is as documented for each related request.
When the content update is applied, the wl_buffer is applied before all
other state. This means that all coordinates in double-buffered state
are relative to the newly attached wl_buffers, except for
wl_surface.attach itself. If there is no newly attached wl_buffer, the
coordinates are relative to the previous content update.
All requests that need a commit to become effective are documented
to affect double-buffered state.
@ -1666,10 +1715,12 @@
<request name="set_buffer_transform" since="2">
<description summary="sets the buffer transformation">
This request sets an optional transformation on how the compositor
interprets the contents of the buffer attached to the surface. The
accepted values for the transform parameter are the values for
wl_output.transform.
This request sets the transformation that the client has already applied
to the content of the buffer. The accepted values for the transform
parameter are the values for wl_output.transform.
The compositor applies the inverse of this transformation whenever it
uses the buffer contents.
Buffer transform is double-buffered state, see wl_surface.commit.
@ -1725,11 +1776,11 @@
a buffer that is larger (by a factor of scale in each dimension)
than the desired surface size.
If scale is not positive the invalid_scale protocol error is
If scale is not greater than 0 the invalid_scale protocol error is
raised.
</description>
<arg name="scale" type="int"
summary="positive scale for interpreting buffer contents"/>
summary="scale for interpreting buffer contents"/>
</request>
<!-- Version 4 additions -->
@ -1784,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.
@ -1802,10 +1856,15 @@
This event indicates the preferred buffer scale for this surface. It is
sent whenever the compositor's preference changes.
Before receiving this event the preferred buffer scale for this surface
is 1.
It is intended that scaling aware clients use this event to scale their
content and use wl_surface.set_buffer_scale to indicate the scale they
have rendered with. This allows clients to supply a higher detail
buffer.
The compositor shall emit a scale value greater than 0.
</description>
<arg name="factor" type="int" summary="preferred scaling factor"/>
</event>
@ -1815,16 +1874,19 @@
This event indicates the preferred buffer transform for this surface.
It is sent whenever the compositor's preference changes.
It is intended that transform aware clients use this event to apply the
transform to their content and use wl_surface.set_buffer_transform to
indicate the transform they have rendered with.
Before receiving this event the preferred buffer transform for this
surface is normal.
Applying this transformation to the surface buffer contents and using
wl_surface.set_buffer_transform might allow the compositor to use the
surface buffer more efficiently.
</description>
<arg name="transform" type="uint" enum="wl_output.transform"
summary="preferred transform"/>
</event>
</interface>
<interface name="wl_seat" version="9">
<interface name="wl_seat" version="10">
<description summary="group of input devices">
A seat is a group of keyboards, pointer and touch devices. This
object is published as a global during start up, or when such a
@ -1852,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
@ -1936,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.
@ -1957,7 +2020,7 @@
</interface>
<interface name="wl_pointer" version="9">
<interface name="wl_pointer" version="10">
<description summary="pointer input device">
The wl_pointer interface represents one or more input devices,
such as mice, which control the pointer location and pointer_focus
@ -1992,9 +2055,9 @@
where (x, y) are the coordinates of the pointer location, in
surface-local coordinates.
On surface.attach requests to the pointer surface, hotspot_x
On wl_surface.offset requests to the pointer surface, hotspot_x
and hotspot_y are decremented by the x and y parameters
passed to the request. Attach must be confirmed by
passed to the request. The offset must be applied by
wl_surface.commit as usual.
The hotspot can also be updated by passing the currently set
@ -2248,7 +2311,7 @@
<arg name="axis" type="uint" enum="axis" summary="the axis stopped with this event"/>
</event>
<event name="axis_discrete" since="5">
<event name="axis_discrete" since="5" deprecated-since="8">
<description summary="axis click event">
Discrete step information for scroll and other axes.
@ -2370,10 +2433,20 @@
</event>
</interface>
<interface name="wl_keyboard" version="9">
<interface name="wl_keyboard" version="10">
<description summary="keyboard input device">
The wl_keyboard interface represents one or more keyboards
associated with a seat.
Each wl_keyboard has the following logical state:
- an active surface (possibly null),
- the keys currently logically down,
- the active modifiers,
- the active group.
By default, the active surface is null, the keys currently logically down
are empty, the active modifiers and the active group are 0.
</description>
<enum name="keymap_format">
@ -2408,10 +2481,18 @@
The compositor must send the wl_keyboard.modifiers event after this
event.
In the wl_keyboard logical state, this event sets the active surface to
the surface argument and the keys currently logically down to the keys
in the keys argument. The compositor must not send this event if the
wl_keyboard already had an active surface immediately before this event.
Clients should not use the list of pressed keys to emulate key-press
events. The order of keys in the list is unspecified.
</description>
<arg name="serial" type="uint" summary="serial number of the enter event"/>
<arg name="surface" type="object" interface="wl_surface" summary="surface gaining keyboard focus"/>
<arg name="keys" type="array" summary="the currently pressed keys"/>
<arg name="keys" type="array" summary="the keys currently logically down"/>
</event>
<event name="leave">
@ -2422,8 +2503,10 @@
The leave notification is sent before the enter notification
for the new focus.
After this event client must assume that all keys, including modifiers,
are lifted and also it must stop key repeating if there's some going on.
In the wl_keyboard logical state, this event resets all values to their
defaults. The compositor must not send this event if the active surface
of the wl_keyboard was not equal to the surface argument immediately
before this event.
</description>
<arg name="serial" type="uint" summary="serial number of the leave event"/>
<arg name="surface" type="object" interface="wl_surface" summary="surface that lost keyboard focus"/>
@ -2432,9 +2515,18 @@
<enum name="key_state">
<description summary="physical key state">
Describes the physical state of a key that produced the key event.
Since version 10, the key can be in a "repeated" pseudo-state which
means the same as "pressed", but is used to signal repetition in the
key event.
The key may only enter the repeated state after entering the pressed
state and before entering the released state. This event may be
generated multiple times while the key is down.
</description>
<entry name="released" value="0" summary="key is not pressed"/>
<entry name="pressed" value="1" summary="key is pressed"/>
<entry name="repeated" value="2" summary="key was repeated" since="10"/>
</enum>
<event name="key">
@ -2448,6 +2540,20 @@
If this event produces a change in modifiers, then the resulting
wl_keyboard.modifiers event must be sent after this event.
In the wl_keyboard logical state, this event adds the key to the keys
currently logically down (if the state argument is pressed) or removes
the key from the keys currently logically down (if the state argument is
released). The compositor must not send this event if the wl_keyboard
did not have an active surface immediately before this event. The
compositor must not send this event if state is pressed (resp. released)
and the key was already logically down (resp. was not logically down)
immediately before this event.
Since version 10, compositors may send key events with the "repeated"
key state when a wl_keyboard.repeat_info event with a rate argument of
0 has been received. This allows the compositor to take over the
responsibility of key repetition.
</description>
<arg name="serial" type="uint" summary="serial number of the key event"/>
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
@ -2459,6 +2565,17 @@
<description summary="modifier and group state">
Notifies clients that the modifier and/or group state has
changed, and it should update its local state.
The compositor may send this event without a surface of the client
having keyboard focus, for example to tie modifier information to
pointer focus instead. If a modifier event with pressed modifiers is sent
without a prior enter event, the client can assume the modifier state is
valid until it receives the next wl_keyboard.modifiers event. In order to
reset the modifier state again, the compositor can send a
wl_keyboard.modifiers event with no pressed modifiers.
In the wl_keyboard logical state, this event updates the modifiers and
group.
</description>
<arg name="serial" type="uint" summary="serial number of the modifiers event"/>
<arg name="mods_depressed" type="uint" summary="depressed modifiers"/>
@ -2497,7 +2614,7 @@
</event>
</interface>
<interface name="wl_touch" version="9">
<interface name="wl_touch" version="10">
<description summary="touchscreen input device">
The wl_touch interface represents a touchscreen
associated with a seat.
@ -2566,6 +2683,8 @@
currently active on this client's surface. The client is
responsible for finalizing the touch points, future touch points on
this surface may reuse the touch point ID.
No frame event is required after the cancel event.
</description>
</event>
@ -2665,10 +2784,9 @@
</enum>
<enum name="transform">
<description summary="transform from framebuffer to output">
This describes the transform that a compositor will apply to a
surface to compensate for the rotation or mirroring of an
output device.
<description summary="transformation applied to buffer contents">
This describes transformations that clients and compositors apply to
buffer contents.
The flipped values correspond to an initial flip around a
vertical axis followed by rotation.
@ -2700,6 +2818,10 @@
The geometry event will be followed by a done event (starting from
version 2).
Clients should use wl_surface.preferred_buffer_transform instead of the
transform advertised by this event to find the preferred buffer
transform to use for a surface.
Note: wl_output only advertises partial information about the output
position and identification. Some compositors, for instance those not
implementing a desktop-style output layout or those exposing virtual
@ -2722,7 +2844,7 @@
<arg name="model" type="string"
summary="textual description of the model"/>
<arg name="transform" type="int" enum="transform"
summary="transform that maps framebuffer to output"/>
summary="additional transformation applied to buffer contents during presentation"/>
</event>
<enum name="mode" bitfield="true">
@ -2795,8 +2917,9 @@
This event contains scaling geometry information
that is not in the geometry event. It may be sent after
binding the output object or if the output scale changes
later. If it is not sent, the client should assume a
scale of 1.
later. The compositor will emit a non-zero, positive
value for scale. If it is not sent, the client should
assume a scale of 1.
A scale larger than 1 means that the compositor will
automatically scale surface buffers by this amount
@ -2804,12 +2927,9 @@
displays where applications rendering at the native
resolution would be too small to be legible.
It is intended that scaling aware clients track the
current output of a surface, and if it is on a scaled
output it should use wl_surface.set_buffer_scale with
the scale of the output. That way the compositor can
avoid scaling the surface, and the client can supply
a higher detail image.
Clients should use wl_surface.preferred_buffer_scale
instead of this event to find the preferred buffer
scale to use for a surface.
The scale event will be followed by a done event.
</description>
@ -3035,6 +3155,11 @@
If the parent wl_surface object is destroyed, the sub-surface is
unmapped.
A sub-surface never has the keyboard focus of any seat.
The wl_surface.offset request is ignored: clients must use set_position
instead to move the sub-surface.
</description>
<request name="destroy" type="destructor">
@ -3060,9 +3185,7 @@
surface area. Negative values are allowed.
The scheduled coordinates will take effect whenever the state of the
parent surface is applied. When this happens depends on whether the
parent surface is in synchronized mode or not. See
wl_subsurface.set_sync and wl_subsurface.set_desync for details.
parent surface is applied.
If more than one set_position request is invoked by the client before
the commit of the parent surface, the position of a new request always
@ -3085,9 +3208,7 @@
The z-order is double-buffered. Requests are handled in order and
applied immediately to a pending state. The final pending state is
copied to the active state the next time the state of the parent
surface is applied. When this happens depends on whether the parent
surface is in synchronized mode or not. See wl_subsurface.set_sync and
wl_subsurface.set_desync for details.
surface is applied.
A new sub-surface is initially added as the top-most in the stack
of its siblings and parent.
@ -3148,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>

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,6 @@
* SOFTWARE.
*/
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
@ -39,9 +38,11 @@
#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"
#include "wayland-server-private.h"
#include "wayland-os.h"
/** \cond INTERNAL */
@ -73,7 +74,7 @@ struct wl_event_loop {
struct wl_list idle_list;
struct wl_list destroy_list;
struct wl_signal destroy_signal;
struct wl_priv_signal destroy_signal;
struct wl_timer_heap timers;
};
@ -446,7 +447,8 @@ wl_timer_heap_disarm(struct wl_timer_heap *timers,
struct wl_event_source_timer *last_end_evt;
int old_source_idx;
assert(source->heap_idx >= 0);
if (!(source->heap_idx >= 0))
wl_abort("Timer has already been disarmed\n");
old_source_idx = source->heap_idx;
source->heap_idx = -1;
@ -475,7 +477,8 @@ wl_timer_heap_arm(struct wl_timer_heap *timers,
struct wl_event_source_timer *source,
struct timespec deadline)
{
assert(source->heap_idx == -1);
if (!(source->heap_idx == -1))
wl_abort("Timer is already armed\n");
source->deadline = deadline;
timers->data[timers->active] = source;
@ -898,7 +901,7 @@ wl_event_loop_create(void)
wl_list_init(&loop->idle_list);
wl_list_init(&loop->destroy_list);
wl_signal_init(&loop->destroy_signal);
wl_priv_signal_init(&loop->destroy_signal);
wl_timer_heap_init(&loop->timers, loop);
@ -921,7 +924,7 @@ wl_event_loop_create(void)
WL_EXPORT void
wl_event_loop_destroy(struct wl_event_loop *loop)
{
wl_signal_emit(&loop->destroy_signal, loop);
wl_priv_signal_final_emit(&loop->destroy_signal, loop);
wl_event_loop_process_destroy_list(loop);
wl_timer_heap_release(&loop->timers);
@ -998,17 +1001,46 @@ wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
struct wl_event_source *source;
int i, count;
bool has_timers = false;
bool use_timeout = timeout > 0;
struct timespec now;
struct timespec deadline = {0};
struct timespec result;
wl_event_loop_dispatch_idle(loop);
count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
if (use_timeout) {
clock_gettime(CLOCK_MONOTONIC, &now);
timespec_add_msec(&deadline, &now, timeout);
}
while (true) {
count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
if (count >= 0)
break; /* have events or timeout */
else if (count < 0 && errno != EINTR && errno != EAGAIN)
break; /* have error */
if (use_timeout) {
clock_gettime(CLOCK_MONOTONIC, &now);
timespec_sub(&result, &deadline, &now);
timeout = timespec_to_msec(&result);
if (timeout <= 0) {
/* too late */
count = 0;
break;
}
}
}
if (count < 0)
return -1;
for (i = 0; i < count; i++) {
source = ep[i].data.ptr;
if (source == &loop->timers.base)
if (source == &loop->timers.base) {
has_timers = true;
break;
}
}
if (has_timers) {
@ -1070,7 +1102,7 @@ WL_EXPORT void
wl_event_loop_add_destroy_listener(struct wl_event_loop *loop,
struct wl_listener *listener)
{
wl_signal_add(&loop->destroy_signal, listener);
wl_priv_signal_add(&loop->destroy_signal, listener);
}
/** Get the listener struct for the specified callback
@ -1086,5 +1118,5 @@ WL_EXPORT struct wl_listener *
wl_event_loop_get_destroy_listener(struct wl_event_loop *loop,
wl_notify_func_t notify)
{
return wl_signal_get(&loop->destroy_signal, notify);
return wl_priv_signal_get(&loop->destroy_signal, notify);
}

View file

@ -65,7 +65,7 @@ if get_option('scanner')
version: meson.project_version(),
variables: [
'datarootdir=' + join_paths('${prefix}', get_option('datadir')),
'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()),
'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()),
'bindir=' + join_paths('${prefix}', get_option('bindir')),
'wayland_scanner=${bindir}/wayland-scanner'
],
@ -74,6 +74,9 @@ if get_option('scanner')
if meson.can_run_host_binaries()
meson.override_find_program('wayland-scanner', wayland_scanner)
meson.override_dependency('wayland-scanner', declare_dependency(
variables: { 'wayland_scanner': 'wayland-scanner' },
))
endif
endif
@ -209,9 +212,10 @@ 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('${datarootdir}', meson.project_name())
'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name())
]
)
@ -248,9 +252,10 @@ 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('${datarootdir}', meson.project_name())
'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name())
]
)

View file

@ -67,7 +67,7 @@ enum visibility {
static int
usage(int ret)
{
fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|private-code|public-code]"
fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|enum-header|private-code|public-code]"
" [input_file output_file]\n", PROGRAM_NAME);
fprintf(stderr, "\n");
fprintf(stderr, "Converts XML protocol descriptions supplied on "
@ -175,7 +175,7 @@ struct interface {
char *name;
char *uppercase_name;
int version;
int since;
int since, deprecated_since;
struct wl_list request_list;
struct wl_list event_list;
struct wl_list enumeration_list;
@ -194,7 +194,7 @@ struct message {
int type_index;
int all_null;
int destructor;
int since;
int since, deprecated_since;
struct description *description;
};
@ -234,7 +234,7 @@ struct entry {
char *uppercase_name;
char *value;
char *summary;
int since;
int since, deprecated_since;
struct wl_list link;
struct description *description;
};
@ -697,6 +697,25 @@ version_from_since(struct parse_context *ctx, const char *since)
return version;
}
static int
version_from_deprecated_since(struct parse_context *ctx, const char *deprecated_since)
{
int version;
if (deprecated_since == NULL)
return 0;
version = strtouint(deprecated_since);
if (version == -1) {
fail(&ctx->loc, "invalid integer (%s)\n", deprecated_since);
} else if (version > ctx->interface->version) {
fail(&ctx->loc, "deprecated-since (%u) larger than version (%u)\n",
version, ctx->interface->version);
}
return version;
}
static void
start_element(void *data, const char *element_name, const char **atts)
{
@ -713,6 +732,7 @@ start_element(void *data, const char *element_name, const char **atts)
const char *value = NULL;
const char *summary = NULL;
const char *since = NULL;
const char *deprecated_since = NULL;
const char *allow_null = NULL;
const char *enumeration_name = NULL;
const char *bitfield = NULL;
@ -737,6 +757,8 @@ start_element(void *data, const char *element_name, const char **atts)
summary = atts[i + 1];
if (strcmp(atts[i], "since") == 0)
since = atts[i + 1];
if (strcmp(atts[i], "deprecated-since") == 0)
deprecated_since = atts[i + 1];
if (strcmp(atts[i], "allow-null") == 0)
allow_null = atts[i + 1];
if (strcmp(atts[i], "enum") == 0)
@ -786,12 +808,18 @@ start_element(void *data, const char *element_name, const char **atts)
message->destructor = 1;
version = version_from_since(ctx, since);
if (version < ctx->interface->since)
warn(&ctx->loc, "since version not increasing\n");
ctx->interface->since = version;
message->since = version;
version = version_from_deprecated_since(ctx, deprecated_since);
if (version > 0 && version <= message->since)
fail(&ctx->loc, "deprecated-since version (%d) smaller "
"or equal to since version (%u)\n",
version, message->since);
message->deprecated_since = version;
if (strcmp(name, "destroy") == 0 && !message->destructor)
fail(&ctx->loc, "destroy request should be destructor type");
@ -872,13 +900,20 @@ start_element(void *data, const char *element_name, const char **atts)
validate_identifier(&ctx->loc, name, TRAILING_IDENT);
entry = create_entry(name, value);
version = version_from_since(ctx, since);
version = version_from_since(ctx, since);
if (version < ctx->enumeration->since)
warn(&ctx->loc, "since version not increasing\n");
ctx->enumeration->since = version;
entry->since = version;
version = version_from_deprecated_since(ctx, deprecated_since);
if (version > 0 && version <= entry->since)
fail(&ctx->loc, "deprecated-since version (%d) smaller "
"or equal to since version (%u)\n",
version, entry->since);
entry->deprecated_since = version;
if (summary)
entry->summary = xstrdup(summary);
else
@ -1344,7 +1379,59 @@ emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
}
static void
emit_enumerations(struct interface *interface)
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"
" *\n"
" * @return true on success, false on error.\n"
" * @ref %s_%s\n"
" */\n"
"static inline bool\n"
"%s_%s_is_valid(uint32_t value, uint32_t version) {\n",
interface->name, interface->name, e->name,
interface->name, e->name,
interface->name, e->name);
if (e->bitfield) {
printf(" uint32_t valid = 0;\n");
wl_list_for_each(entry, &e->entry_list, link) {
printf(" if (version >= %d)\n"
" valid |= %s_%s_%s;\n",
entry->since,
interface->uppercase_name, e->uppercase_name,
entry->uppercase_name);
}
printf(" return (value & ~valid) == 0;\n");
} else {
printf(" switch (value) {\n");
wl_list_for_each(entry, &e->entry_list, link) {
printf(" case %s%s_%s_%s:\n"
" return version >= %d;\n",
entry->value[0] == '-' ? "(uint32_t)" : "",
interface->uppercase_name, e->uppercase_name,
entry->uppercase_name, entry->since);
}
printf(" default:\n"
" return false;\n"
" }\n");
}
printf("}\n");
printf("#endif /* %s_%s_ENUM_IS_VALID */\n\n",
interface->uppercase_name, e->uppercase_name);
}
static void
emit_enumerations(struct interface *interface, bool with_validators)
{
struct enumeration *e;
struct entry *entry;
@ -1380,6 +1467,9 @@ emit_enumerations(struct interface *interface)
}
if (entry->since > 1)
printf("\t * @since %d\n", entry->since);
if (entry->deprecated_since > 0)
printf("\t * @deprecated Deprecated since version %d\n",
entry->deprecated_since);
printf("\t */\n");
}
printf("\t%s_%s_%s = %s,\n",
@ -1403,6 +1493,9 @@ emit_enumerations(struct interface *interface)
printf("#endif /* %s_%s_ENUM */\n\n",
interface->uppercase_name, e->uppercase_name);
if (with_validators)
emit_validator(interface, e);
}
}
@ -1444,9 +1537,11 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid
printf("\t * @param %s %s\n", a->name,
a->summary);
}
if (m->since > 1) {
if (m->since > 1)
printf("\t * @since %d\n", m->since);
}
if (m->deprecated_since > 0)
printf("\t * @deprecated Deprecated since version %d\n",
m->deprecated_since);
printf("\t */\n");
printf("\tvoid (*%s)(", m->name);
@ -1677,7 +1772,7 @@ emit_header(struct protocol *protocol, enum side side)
wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) {
emit_enumerations(i);
emit_enumerations(i, side == SERVER);
if (side == SERVER) {
emit_structs(&i->request_list, i, side);
@ -1703,6 +1798,35 @@ emit_header(struct protocol *protocol, enum side side)
"#endif\n");
}
static void
emit_enum_header(struct protocol *protocol)
{
struct interface *i, *i_next;
printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
printf("#ifndef %s_ENUM_PROTOCOL_H\n"
"#define %s_ENUM_PROTOCOL_H\n"
"\n"
"#ifdef __cplusplus\n"
"extern \"C\" {\n"
"#endif\n\n",
protocol->uppercase_name,
protocol->uppercase_name);
wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) {
emit_enumerations(i, false);
free_interface(i);
}
printf("#ifdef __cplusplus\n"
"}\n"
"#endif\n"
"\n"
"#endif\n");
}
static void
emit_null_run(struct protocol *protocol)
{
@ -1820,7 +1944,8 @@ emit_code(struct protocol *protocol, enum visibility vis)
if (protocol->copyright)
format_text_to_comment(protocol->copyright, true);
printf("#include <stdlib.h>\n"
printf("#include <stdbool.h>\n"
"#include <stdlib.h>\n"
"#include <stdint.h>\n"
"#include \"wayland-util.h\"\n\n");
@ -1923,6 +2048,7 @@ int main(int argc, char *argv[])
enum {
CLIENT_HEADER,
SERVER_HEADER,
ENUM_HEADER,
PRIVATE_CODE,
PUBLIC_CODE,
CODE,
@ -1976,6 +2102,8 @@ int main(int argc, char *argv[])
mode = CLIENT_HEADER;
else if (strcmp(argv[0], "server-header") == 0)
mode = SERVER_HEADER;
else if (strcmp(argv[0], "enum-header") == 0)
mode = ENUM_HEADER;
else if (strcmp(argv[0], "private-code") == 0)
mode = PRIVATE_CODE;
else if (strcmp(argv[0], "public-code") == 0)
@ -2067,6 +2195,9 @@ int main(int argc, char *argv[])
case SERVER_HEADER:
emit_header(&protocol, SERVER);
break;
case ENUM_HEADER:
emit_enum_header(&protocol);
break;
case PRIVATE_CODE:
emit_code(&protocol, PRIVATE);
break;

311
src/timespec-util.h Normal file
View 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 */

View file

@ -34,6 +34,8 @@
extern "C" {
#endif
struct timespec;
/** \class wl_proxy
*
* \brief Represents a protocol object on the client side.
@ -120,7 +122,7 @@ struct wl_display;
struct wl_event_queue;
/** Destroy proxy after marshalling
* @ingroup wl_proxy
* \relates wl_proxy
*/
#define WL_MARSHAL_FLAG_DESTROY (1 << 0)
@ -219,9 +221,21 @@ 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);
void
wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue);
struct wl_event_queue *
wl_proxy_get_queue(const struct wl_proxy *proxy);
const char *
wl_event_queue_get_name(const struct wl_event_queue *queue);
struct wl_display *
wl_display_connect(const char *name);
@ -241,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);
@ -269,6 +299,10 @@ wl_display_roundtrip(struct wl_display *display);
struct wl_event_queue *
wl_display_create_queue(struct wl_display *display);
struct wl_event_queue *
wl_display_create_queue_with_name(struct wl_display *display,
const char *name);
int
wl_display_prepare_read_queue(struct wl_display *display,
struct wl_event_queue *queue);
@ -285,6 +319,10 @@ wl_display_read_events(struct wl_display *display);
void
wl_log_set_handler_client(wl_log_func_t handler);
void
wl_display_set_max_buffer_size(struct wl_display *display,
size_t max_buffer_size);
#ifdef __cplusplus
}
#endif

View file

@ -37,7 +37,6 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <ctype.h>
#include <assert.h>
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
@ -46,6 +45,7 @@
#include "wayland-os.h"
#include "wayland-client.h"
#include "wayland-private.h"
#include "timespec-util.h"
/** \cond */
@ -77,6 +77,7 @@ struct wl_event_queue {
struct wl_list event_list;
struct wl_list proxy_list; /**< struct wl_proxy::queue_link */
struct wl_display *display;
char *name;
};
struct wl_display {
@ -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
@ -220,23 +222,30 @@ display_protocol_error(struct wl_display *display, uint32_t code,
}
static void
wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display)
wl_event_queue_init(struct wl_event_queue *queue,
struct wl_display *display,
const char *name)
{
wl_list_init(&queue->event_list);
wl_list_init(&queue->proxy_list);
queue->display = display;
if (name)
queue->name = strdup(name);
}
static void
wl_proxy_unref(struct wl_proxy *proxy)
{
assert(proxy->refcount > 0);
if (!(proxy->refcount > 0))
wl_abort("Proxy requested for unref has no references\n");
if (--proxy->refcount > 0)
return;
/* If we get here, the client must have explicitly requested
* deletion. */
assert(proxy->flags & WL_PROXY_FLAG_DESTROYED);
if (!(proxy->flags & WL_PROXY_FLAG_DESTROYED))
wl_abort("Proxy with no references not yet explicitly"
"destroyed\n");
free(proxy);
}
@ -253,8 +262,8 @@ validate_closure_objects(struct wl_closure *closure)
for (i = 0; i < count; i++) {
signature = get_next_argument(signature, &arg);
switch (arg.type) {
case 'n':
case 'o':
case WL_ARG_NEW_ID:
case WL_ARG_OBJECT:
proxy = (struct wl_proxy *) closure->args[i].o;
if (proxy && proxy->flags & WL_PROXY_FLAG_DESTROYED)
closure->args[i].o = NULL;
@ -281,8 +290,8 @@ destroy_queued_closure(struct wl_closure *closure)
for (i = 0; i < count; i++) {
signature = get_next_argument(signature, &arg);
switch (arg.type) {
case 'n':
case 'o':
case WL_ARG_NEW_ID:
case WL_ARG_OBJECT:
proxy = (struct wl_proxy *) closure->args[i].o;
if (proxy)
wl_proxy_unref(proxy);
@ -305,14 +314,21 @@ wl_event_queue_release(struct wl_event_queue *queue)
struct wl_proxy *proxy, *tmp;
if (queue != &queue->display->default_queue) {
wl_log("warning: queue %p destroyed while proxies "
"still attached:\n", queue);
if (queue->name) {
wl_log("warning: queue \"%s\" "
"%p destroyed while proxies "
"still attached:\n", queue->name, queue);
} else {
wl_log("warning: queue "
"%p destroyed while proxies "
"still attached:\n", queue);
}
}
wl_list_for_each_safe(proxy, tmp, &queue->proxy_list,
queue_link) {
if (queue != &queue->display->default_queue) {
wl_log(" %s@%u still attached\n",
wl_log(" %s#%u still attached\n",
proxy->object.interface->name,
proxy->object.id);
}
@ -350,6 +366,7 @@ wl_event_queue_destroy(struct wl_event_queue *queue)
pthread_mutex_lock(&display->mutex);
wl_event_queue_release(queue);
free(queue->name);
free(queue);
pthread_mutex_unlock(&display->mutex);
}
@ -371,7 +388,30 @@ wl_display_create_queue(struct wl_display *display)
if (queue == NULL)
return NULL;
wl_event_queue_init(queue, display);
wl_event_queue_init(queue, display, NULL);
return queue;
}
/** Create a new event queue for this display and give it a name
*
* \param display The display context object
* \param name A human readable queue name
* \return A new event queue associated with this display or NULL on
* failure.
*
* \memberof wl_display
*/
WL_EXPORT struct wl_event_queue *
wl_display_create_queue_with_name(struct wl_display *display, const char *name)
{
struct wl_event_queue *queue;
queue = zalloc(sizeof *queue);
if (queue == NULL)
return NULL;
wl_event_queue_init(queue, display, name);
return queue;
}
@ -385,7 +425,7 @@ message_count_fds(const char *signature)
count = arg_count_for_signature(signature);
for (i = 0; i < count; i++) {
signature = get_next_argument(signature, &arg);
if (arg.type == 'h')
if (arg.type == WL_ARG_FD)
fds++;
}
@ -635,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 *
@ -697,16 +740,14 @@ create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message,
count = arg_count_for_signature(signature);
for (i = 0; i < count; i++) {
signature = get_next_argument(signature, &arg);
if (arg.type != WL_ARG_NEW_ID)
continue;
switch (arg.type) {
case 'n':
new_proxy = proxy_create(proxy, interface, version);
if (new_proxy == NULL)
return NULL;
new_proxy = proxy_create(proxy, interface, version);
if (new_proxy == NULL)
return NULL;
args[i].o = &new_proxy->object;
break;
}
args[i].o = &new_proxy->object;
}
return new_proxy;
@ -880,16 +921,29 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
closure = wl_closure_marshal(&proxy->object, opcode, args, message);
if (closure == NULL) {
wl_log("Error marshalling request: %s\n", strerror(errno));
wl_log("Error marshalling request for %s.%s: %s\n",
proxy->object.interface->name, message->name,
strerror(errno));
display_fatal_error(proxy->display, errno);
goto err_unlock;
}
if (debug_client)
wl_closure_print(closure, &proxy->object, true, false, NULL);
if (debug_client) {
struct wl_event_queue *queue;
const char *queue_name = NULL;
queue = wl_proxy_get_queue(proxy);
if (queue)
queue_name = wl_event_queue_get_name(queue);
wl_closure_print(closure, &proxy->object, true, false, NULL,
queue_name, debug_color);
}
if (wl_closure_send(closure, proxy->display->connection)) {
wl_log("Error sending request: %s\n", strerror(errno));
wl_log("Error sending request for %s.%s: %s\n",
proxy->object.interface->name, message->name,
strerror(errno));
display_fatal_error(proxy->display, errno);
}
@ -1045,7 +1099,7 @@ display_handle_error(void *data,
const struct wl_interface *interface;
if (proxy) {
wl_log("%s@%u: error %d: %s\n",
wl_log("%s#%u: error %d: %s\n",
proxy->object.interface->name,
proxy->object.id,
code, message);
@ -1133,7 +1187,8 @@ connect_to_socket(const char *name)
"%s", name) + 1;
}
assert(name_size > 0);
if (!(name_size > 0))
wl_abort("Error assigning path name for socket connection\n");
if (name_size > (int)sizeof addr.sun_path) {
if (!path_is_absolute) {
wl_log("error: socket path \"%s/%s\" plus null terminator"
@ -1175,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) {
@ -1188,8 +1256,8 @@ wl_display_connect_to_fd(int fd)
display->fd = fd;
wl_map_init(&display->objects, WL_MAP_CLIENT_SIDE);
wl_event_queue_init(&display->default_queue, display);
wl_event_queue_init(&display->display_queue, display);
wl_event_queue_init(&display->default_queue, display, "Default Queue");
wl_event_queue_init(&display->display_queue, display, "Display Queue");
pthread_mutex_init(&display->mutex, NULL);
pthread_cond_init(&display->reader_cond, NULL);
display->reader_count = 0;
@ -1230,7 +1298,7 @@ wl_display_connect_to_fd(int fd)
*/
display->proxy.version = 0;
display->connection = wl_connection_create(display->fd);
display->connection = wl_connection_create(display->fd, 0);
if (display->connection == NULL)
goto err_connection;
@ -1321,7 +1389,9 @@ wl_display_disconnect(struct wl_display *display)
wl_map_for_each(&display->objects, free_zombies, NULL);
wl_map_release(&display->objects);
wl_event_queue_release(&display->default_queue);
free(display->default_queue.name);
wl_event_queue_release(&display->display_queue);
free(display->display_queue.name);
pthread_mutex_destroy(&display->mutex);
pthread_cond_destroy(&display->reader_cond);
close(display->fd);
@ -1446,22 +1516,19 @@ create_proxies(struct wl_proxy *sender, struct wl_closure *closure)
count = arg_count_for_signature(signature);
for (i = 0; i < count; i++) {
signature = get_next_argument(signature, &arg);
switch (arg.type) {
case 'n':
id = closure->args[i].n;
if (id == 0) {
closure->args[i].o = NULL;
break;
}
proxy = wl_proxy_create_for_id(sender, id,
closure->message->types[i]);
if (proxy == NULL)
return -1;
closure->args[i].o = (struct wl_object *)proxy;
break;
default:
break;
if (arg.type != WL_ARG_NEW_ID)
continue;
id = closure->args[i].n;
if (id == 0) {
closure->args[i].o = NULL;
continue;
}
proxy = wl_proxy_create_for_id(sender, id,
closure->message->types[i]);
if (proxy == NULL)
return -1;
closure->args[i].o = (struct wl_object *)proxy;
}
return 0;
@ -1480,8 +1547,8 @@ increase_closure_args_refcount(struct wl_closure *closure)
for (i = 0; i < count; i++) {
signature = get_next_argument(signature, &arg);
switch (arg.type) {
case 'n':
case 'o':
case WL_ARG_NEW_ID:
case WL_ARG_OBJECT:
proxy = (struct wl_proxy *) closure->args[i].o;
if (proxy)
proxy->refcount++;
@ -1511,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;
@ -1525,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)
@ -1609,9 +1702,16 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
validate_closure_objects(closure);
proxy = closure->proxy;
proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED);
if (debug_client) {
bool discarded = proxy_destroyed ||
!(proxy->dispatcher || proxy->object.implementation);
wl_closure_print(closure, &proxy->object, false, discarded,
id_from_object, queue->name, debug_color);
}
if (proxy_destroyed) {
if (debug_client)
wl_closure_print(closure, &proxy->object, false, true, id_from_object);
destroy_queued_closure(closure);
return;
}
@ -1619,15 +1719,9 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
pthread_mutex_unlock(&display->mutex);
if (proxy->dispatcher) {
if (debug_client)
wl_closure_print(closure, &proxy->object, false, false, id_from_object);
wl_closure_dispatch(closure, proxy->dispatcher,
&proxy->object, opcode);
} else if (proxy->object.implementation) {
if (debug_client)
wl_closure_print(closure, &proxy->object, false, false, id_from_object);
wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT,
&proxy->object, opcode, proxy->user_data);
}
@ -1788,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
@ -1903,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
@ -1948,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()
@ -1962,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
@ -2023,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
@ -2083,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
@ -2197,6 +2461,32 @@ wl_display_flush(struct wl_display *display)
return ret;
}
/** Adjust the maximum size of the client connection buffers
*
* \param display The display context object
* \param max_buffer_size The maximum size of the connection buffers
*
* Client buffers are unbounded by default. This function sets a limit to the
* size of the connection buffers.
*
* A value of 0 for \a max_buffer_size requests the buffers to be unbounded.
*
* The actual size of the connection buffers is a power of two, the requested
* \a max_buffer_size is therefore rounded up to the nearest power of two value.
*
* Lowering the maximum size may not take effect immediately if the current
* content of the buffer does not fit within the new size limit.
*
* \memberof wl_display
* \since 1.22.90
*/
WL_EXPORT void
wl_display_set_max_buffer_size(struct wl_display *display,
size_t max_buffer_size)
{
wl_connection_set_max_buffer_size(display->connection, max_buffer_size);
}
/** Set the user data associated with a proxy
*
* \param proxy The proxy object
@ -2338,6 +2628,34 @@ 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
* \return The wl_display the proxy is associated with
*
* \memberof wl_proxy
* \since 1.23
*/
WL_EXPORT struct wl_display *
wl_proxy_get_display(struct wl_proxy *proxy)
{
return proxy->display;
}
/** Assign a proxy to an event queue
*
* \param proxy The proxy object
@ -2374,7 +2692,9 @@ wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue)
wl_list_remove(&proxy->queue_link);
if (queue) {
assert(proxy->display == queue->display);
if (!(proxy->display == queue->display))
wl_abort("Proxy and queue point to different "
"wl_displays");
proxy->queue = queue;
} else {
proxy->queue = &proxy->display->default_queue;
@ -2385,6 +2705,34 @@ wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue)
pthread_mutex_unlock(&proxy->display->mutex);
}
/** Get a proxy's event queue
*
* \param proxy The proxy to query
*
* Return the event queue
*/
WL_EXPORT struct wl_event_queue *
wl_proxy_get_queue(const struct wl_proxy *proxy)
{
return proxy->queue;
}
/** Get the name of an event queue
*
* \param queue The queue to query
*
* Return the human readable name for the event queue
*
* This may be NULL if no name has been set.
*
* \memberof wl_proxy
*/
WL_EXPORT const char *
wl_event_queue_get_name(const struct wl_event_queue *queue)
{
return queue->name;
}
/** Create a proxy wrapper for making queue assignments thread-safe
*
* \param proxy The proxy object to be wrapped
@ -2474,7 +2822,8 @@ wl_proxy_wrapper_destroy(void *proxy_wrapper)
wl_abort("Tried to destroy non-wrapper proxy with "
"wl_proxy_wrapper_destroy\n");
assert(wrapper->refcount == 1);
if (!(wrapper->refcount == 1))
wl_abort("Expected proxy wrapper's refcount to be 1\n");
pthread_mutex_lock(&wrapper->display->mutex);

View file

@ -42,6 +42,12 @@
#include "wayland-os.h"
/* used by tests */
int (*wl_fcntl)(int fildes, int cmd, ...) = fcntl;
int (*wl_socket)(int domain, int type, int protocol) = socket;
ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags) = recvmsg;
int (*wl_epoll_create1)(int flags) = epoll_create1;
static int
set_cloexec_or_close(int fd)
{
@ -50,11 +56,11 @@ set_cloexec_or_close(int fd)
if (fd == -1)
return -1;
flags = fcntl(fd, F_GETFD);
flags = wl_fcntl(fd, F_GETFD);
if (flags == -1)
goto err;
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
if (wl_fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
goto err;
return fd;
@ -69,13 +75,13 @@ wl_os_socket_cloexec(int domain, int type, int protocol)
{
int fd;
fd = socket(domain, type | SOCK_CLOEXEC, protocol);
fd = wl_socket(domain, type | SOCK_CLOEXEC, protocol);
if (fd >= 0)
return fd;
if (errno != EINVAL)
return -1;
fd = socket(domain, type, protocol);
fd = wl_socket(domain, type, protocol);
return set_cloexec_or_close(fd);
}
@ -105,7 +111,11 @@ int
wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid)
{
socklen_t len;
#if defined(__OpenBSD__)
struct sockpeercred ucred;
#else
struct ucred ucred;
#endif
len = sizeof(ucred);
if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0)
@ -124,13 +134,13 @@ wl_os_dupfd_cloexec(int fd, int minfd)
{
int newfd;
newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
newfd = wl_fcntl(fd, F_DUPFD_CLOEXEC, minfd);
if (newfd >= 0)
return newfd;
if (errno != EINVAL)
return -1;
newfd = fcntl(fd, F_DUPFD, minfd);
newfd = wl_fcntl(fd, F_DUPFD, minfd);
return set_cloexec_or_close(newfd);
}
@ -143,7 +153,7 @@ recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags)
int *fd;
int *end;
len = recvmsg(sockfd, msg, flags);
len = wl_recvmsg(sockfd, msg, flags);
if (len == -1)
return -1;
@ -179,7 +189,7 @@ wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
#else
ssize_t len;
len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
len = wl_recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
if (len >= 0)
return len;
if (errno != EINVAL)
@ -194,7 +204,7 @@ wl_os_epoll_create_cloexec(void)
int fd;
#ifdef EPOLL_CLOEXEC
fd = epoll_create1(EPOLL_CLOEXEC);
fd = wl_epoll_create1(EPOLL_CLOEXEC);
if (fd >= 0)
return fd;
if (errno != EINVAL)

View file

@ -47,6 +47,33 @@
#define WL_SERVER_ID_START 0xff000000
#define WL_MAP_MAX_OBJECTS 0x00f00000
#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.
*/
enum wl_arg_type {
WL_ARG_INT = 'i',
WL_ARG_UINT = 'u',
WL_ARG_FIXED = 'f',
WL_ARG_STRING = 's',
WL_ARG_OBJECT = 'o',
WL_ARG_NEW_ID = 'n',
WL_ARG_ARRAY = 'a',
WL_ARG_FD = 'h',
};
struct wl_object {
const struct wl_interface *interface;
@ -106,7 +133,7 @@ void
wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data);
struct wl_connection *
wl_connection_create(int fd);
wl_connection_create(int fd, size_t max_buffer_size);
int
wl_connection_destroy(struct wl_connection *connection);
@ -149,7 +176,7 @@ struct wl_closure {
};
struct argument_details {
char type;
enum wl_arg_type type;
int nullable;
};
@ -210,10 +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));
uint32_t (*n_parse)(union wl_argument *arg),
const char *queue_name, int color);
void
wl_closure_destroy(struct wl_closure *closure);
@ -237,4 +268,8 @@ zalloc(size_t s)
void
wl_connection_close_fds_in(struct wl_connection *connection, int max);
void
wl_connection_set_max_buffer_size(struct wl_connection *connection,
size_t max_buffer_size);
#endif

View file

@ -217,13 +217,17 @@ wl_display_flush_clients(struct wl_display *display);
void
wl_display_destroy_clients(struct wl_display *display);
void
wl_display_set_default_max_buffer_size(struct wl_display *display,
size_t max_buffer_size);
struct wl_client;
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);
@ -320,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
@ -365,6 +369,19 @@ wl_client_for_each_resource(struct wl_client *client,
wl_client_for_each_resource_iterator_func_t iterator,
void *user_data);
typedef void (*wl_user_data_destroy_func_t)(void *data);
void
wl_client_set_user_data(struct wl_client *client,
void *data,
wl_user_data_destroy_func_t dtor);
void *
wl_client_get_user_data(struct wl_client *client);
void
wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size);
/** \class wl_listener
*
* \brief A single listener for Wayland signals
@ -533,7 +550,10 @@ void
wl_resource_queue_event_array(struct wl_resource *resource,
uint32_t opcode, union wl_argument *args);
/* msg is a printf format string, variable args are its args. */
void
wl_resource_post_error_vargs(struct wl_resource *resource,
uint32_t code, const char *msg, va_list argp);
void
wl_resource_post_error(struct wl_resource *resource,
uint32_t code, const char *msg, ...) WL_PRINTF(3, 4);
@ -566,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);
@ -587,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,
@ -597,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,
@ -634,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);
@ -657,10 +687,11 @@ wl_display_init_shm(struct wl_display *display);
uint32_t *
wl_display_add_shm_format(struct wl_display *display, uint32_t format);
WL_DEPRECATED
struct wl_shm_buffer *
wl_shm_buffer_create(struct wl_client *client,
uint32_t id, int32_t width, int32_t height,
int32_t stride, uint32_t format) WL_DEPRECATED;
int32_t stride, uint32_t format);
void
wl_log_set_handler_server(wl_log_func_t handler);

View file

@ -37,7 +37,6 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <dlfcn.h>
#include <assert.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/eventfd.h>
@ -83,13 +82,15 @@ struct wl_client {
pid_t pid;
uid_t uid;
gid_t gid;
int error;
bool error;
struct wl_priv_signal resource_created_signal;
void *data;
wl_user_data_destroy_func_t data_dtor;
};
struct wl_display {
struct wl_event_loop *loop;
int run;
bool run;
uint32_t next_global_name;
uint32_t serial;
@ -110,6 +111,8 @@ struct wl_display {
int terminate_efd;
struct wl_event_source *term_source;
size_t max_buffer_size;
};
struct wl_global {
@ -146,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,
@ -157,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);
wl_closure_print(closure, object, send, false, NULL, NULL, debug_color);
if (!wl_list_empty(&display->protocol_loggers)) {
message.resource = resource;
@ -189,8 +193,8 @@ verify_objects(struct wl_resource *resource, uint32_t opcode,
for (i = 0; i < count; i++) {
signature = get_next_argument(signature, &arg);
switch (arg.type) {
case 'n':
case 'o':
case WL_ARG_NEW_ID:
case WL_ARG_OBJECT:
res = (struct wl_resource *) (args[i].o);
if (res && res->client != resource->client) {
wl_log("compositor bug: The compositor "
@ -200,6 +204,8 @@ verify_objects(struct wl_resource *resource, uint32_t opcode,
object->interface->events[opcode].name);
return false;
}
default:
break;
}
}
return true;
@ -217,7 +223,7 @@ handle_array(struct wl_resource *resource, uint32_t opcode,
return;
if (!verify_objects(resource, opcode, args)) {
resource->client->error = 1;
resource->client->error = true;
return;
}
@ -225,14 +231,14 @@ handle_array(struct wl_resource *resource, uint32_t opcode,
&object->interface->events[opcode]);
if (closure == NULL) {
resource->client->error = 1;
resource->client->error = true;
return;
}
log_closure(resource, closure, true);
if (send_func(closure, resource->client->connection))
resource->client->error = 1;
resource->client->error = true;
wl_closure_destroy(closure);
}
@ -282,7 +288,16 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
wl_resource_queue_event_array(resource, opcode, args);
}
static void
/** Post a protocol error
*
* \param resource The resource object
* \param code The error code
* \param msg The error message format string
* \param argp The format string argument list
*
* \memberof wl_resource
*/
WL_EXPORT void
wl_resource_post_error_vargs(struct wl_resource *resource,
uint32_t code, const char *msg, va_list argp)
{
@ -303,10 +318,18 @@ wl_resource_post_error_vargs(struct wl_resource *resource,
wl_resource_post_event(client->display_resource,
WL_DISPLAY_ERROR, resource, code, buffer);
client->error = 1;
client->error = true;
}
/** Post a protocol error
*
* \param resource The resource object
* \param code The error code
* \param msg The error message format string
* \param ... The format string arguments
*
* \memberof wl_resource
*/
WL_EXPORT void
wl_resource_post_error(struct wl_resource *resource,
uint32_t code, const char *msg, ...)
@ -375,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;
@ -391,7 +437,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
if (opcode >= object->interface->method_count) {
wl_resource_post_error(client->display_resource,
WL_DISPLAY_ERROR_INVALID_METHOD,
"invalid method %d, object %s@%u",
"invalid method %d, object %s#%u",
opcode,
object->interface->name,
object->id);
@ -405,7 +451,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
wl_resource_post_error(client->display_resource,
WL_DISPLAY_ERROR_INVALID_METHOD,
"invalid method %d (since %d < %d)"
", object %s@%u",
", object %s#%u",
opcode, resource->version, since,
object->interface->name,
object->id);
@ -423,7 +469,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
wl_closure_lookup_objects(closure, &client->objects) < 0) {
wl_resource_post_error(client->display_resource,
WL_DISPLAY_ERROR_INVALID_METHOD,
"invalid arguments for %s@%u.%s",
"invalid arguments for %s#%u.%s",
object->interface->name,
object->id,
message->name);
@ -514,6 +560,11 @@ bind_display(struct wl_client *client, struct wl_display *display);
*
* On failure this function sets errno accordingly and returns NULL.
*
* On success, the new client object takes the ownership of the file
* descriptor. On failure, the ownership of the socket endpoint file
* descriptor is unchanged, it is the responsibility of the caller to
* perform cleanup, e.g. call close().
*
* \memberof wl_display
*/
WL_EXPORT struct wl_client *
@ -538,7 +589,8 @@ wl_client_create(struct wl_display *display, int fd)
&client->pid) != 0)
goto err_source;
client->connection = wl_connection_create(fd);
client->connection = wl_connection_create(fd, display->max_buffer_size);
if (client->connection == NULL)
goto err_source;
@ -591,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)
@ -717,10 +769,23 @@ resource_is_deprecated(struct wl_resource *resource)
return false;
}
/** Removes the wl_resource from the client's object map and deletes it.
*
* Triggers the destroy signal and destructor for the resource before
* removing it from the client's object map and releasing the resource's
* memory.
*
* This order is important to ensure listeners and destruction code can
* find the resource before it has been destroyed whilst ensuring the
* resource is not accessible via the object map after memory has been
* freed.
*/
static enum wl_iterator_result
destroy_resource(void *element, void *data, uint32_t flags)
remove_and_destroy_resource(void *element, void *data, uint32_t flags)
{
struct wl_resource *resource = element;
struct wl_client *client = resource->client;
uint32_t id = resource->object.id;;
wl_signal_emit(&resource->deprecated_destroy_signal, resource);
/* Don't emit the new signal for deprecated resources, as that would
@ -731,6 +796,17 @@ destroy_resource(void *element, void *data, uint32_t flags)
if (resource->destroy)
resource->destroy(resource);
/* The resource should be cleared from the map before memory is freed. */
if (id < WL_SERVER_ID_START) {
if (client->display_resource) {
wl_resource_queue_event(client->display_resource,
WL_DISPLAY_DELETE_ID, id);
}
wl_map_insert_at(&client->objects, 0, id, NULL);
} else {
wl_map_remove(&client->objects, id);
}
if (!(flags & WL_MAP_ENTRY_LEGACY))
free(resource);
@ -741,26 +817,13 @@ WL_EXPORT void
wl_resource_destroy(struct wl_resource *resource)
{
struct wl_client *client = resource->client;
uint32_t id;
uint32_t flags;
uint32_t flags = wl_map_lookup_flags(&client->objects, resource->object.id);
id = resource->object.id;
flags = wl_map_lookup_flags(&client->objects, id);
destroy_resource(resource, NULL, flags);
if (id < WL_SERVER_ID_START) {
if (client->display_resource) {
wl_resource_queue_event(client->display_resource,
WL_DISPLAY_DELETE_ID, id);
}
wl_map_insert_at(&client->objects, 0, id, NULL);
} else {
wl_map_remove(&client->objects, id);
}
remove_and_destroy_resource(resource, NULL, flags);
}
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;
}
@ -814,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;
}
@ -861,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
*
@ -920,20 +997,33 @@ wl_client_get_destroy_late_listener(struct wl_client *client,
WL_EXPORT void
wl_client_destroy(struct wl_client *client)
{
uint32_t serial = 0;
/* wl_client_destroy() should not be called twice for the same client. */
if (wl_list_empty(&client->link)) {
client->error = 1;
wl_log("wl_client_destroy: encountered re-entrant client destruction.\n");
return;
}
wl_list_remove(&client->link);
/* Keep the client link safe to inspect. */
wl_list_init(&client->link);
wl_priv_signal_final_emit(&client->destroy_signal, client);
wl_client_flush(client);
wl_map_for_each(&client->objects, destroy_resource, &serial);
wl_map_for_each(&client->objects, remove_and_destroy_resource, NULL);
wl_map_release(&client->objects);
wl_event_source_remove(client->source);
close(wl_connection_destroy(client->connection));
wl_priv_signal_final_emit(&client->destroy_late_signal, client);
wl_list_remove(&client->link);
wl_list_remove(&client->resource_created_signal.listener_list);
if (client->data_dtor)
client->data_dtor(client->data);
free(client);
}
@ -1102,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)
@ -1144,6 +1247,7 @@ wl_display_create(void)
display->global_filter = NULL;
display->global_filter_data = NULL;
display->max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE;
wl_array_init(&display->additional_shm_formats);
@ -1343,7 +1447,7 @@ wl_global_remove(struct wl_global *global)
if (global->removed)
wl_abort("wl_global_remove: called twice on the same "
"global '%s@%"PRIu32"'", global->interface->name,
"global '%s#%"PRIu32"'", global->interface->name,
global->name);
wl_list_for_each(resource, &display->registry_resource_list, link)
@ -1443,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;
}
@ -1477,20 +1581,23 @@ wl_display_terminate(struct wl_display *display)
int ret;
uint64_t terminate = 1;
display->run = 0;
display->run = false;
ret = write(display->terminate_efd, &terminate, sizeof(terminate));
assert (ret >= 0 || errno == EAGAIN);
if (ret < 0 && errno != EAGAIN)
wl_abort("Write failed at shutdown\n");
}
WL_EXPORT void
wl_display_run(struct wl_display *display)
{
display->run = 1;
display->run = true;
while (display->run) {
wl_display_flush_clients(display);
wl_event_loop_dispatch(display->loop, -1);
if (wl_event_loop_dispatch(display->loop, -1) < 0) {
break;
}
}
}
@ -1550,6 +1657,37 @@ wl_display_destroy_clients(struct wl_display *display)
}
}
/** Sets the default maximum size for connection buffers of new clients
*
* \param display The display object
* \param max_buffer_size The default maximum size of the connection buffers
*
* This function sets the default size of the internal connection buffers for
* new clients. It doesn't change the buffer size for existing wl_client.
*
* The connection buffer size of an existing wl_client can be adjusted using
* wl_client_set_max_buffer_size().
*
* The actual size of the connection buffers is a power of two, the requested
* \a max_buffer_size is therefore rounded up to the nearest power of two value.
*
* The minimum buffer size is 4096.
*
* \sa wl_client_set_max_buffer_size
*
* \memberof wl_display
* \since 1.22.90
*/
WL_EXPORT void
wl_display_set_default_max_buffer_size(struct wl_display *display,
size_t max_buffer_size)
{
if (max_buffer_size < WL_BUFFER_DEFAULT_MAX_SIZE)
max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE;
display->max_buffer_size = max_buffer_size;
}
static int
socket_data(int fd, uint32_t mask, void *data)
{
@ -1644,7 +1782,8 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path,
"%s%s%s", runtime_dir, separator, name) + 1;
assert(name_size > 0);
if (!(name_size > 0))
wl_abort("Error assigning path name for socket address\n");
if (name_size > (int)sizeof s->addr.sun_path) {
wl_log("error: socket path \"%s%s%s\" plus null terminator"
" exceeds 108 bytes\n", runtime_dir, separator, name);
@ -1692,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)
{
@ -1741,6 +1898,9 @@ wl_display_add_socket_auto(struct wl_display *display)
* The fd must be properly set to CLOEXEC and bound to a socket file
* with both bind() and listen() already called.
*
* On success, the socket fd ownership is transferred to libwayland:
* libwayland will close the socket when the display is destroyed.
*
* \memberof wl_display
*/
WL_EXPORT int
@ -1969,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
*
@ -2245,6 +2405,34 @@ wl_signal_emit_mutable(struct wl_signal *signal, void *data)
wl_list_remove(&end.link);
}
/** Adjust the maximum size of the client connection buffers
*
* \param client The client object
* \param max_buffer_size The maximum size of the connection buffers
*
* The actual size of the connection buffers is a power of two, the requested
* \a max_buffer_size is therefore rounded up to the nearest power of two value.
*
* Lowering the maximum size may not take effect immediately if the current content
* of the buffer does not fit within the new size limit.
*
* The minimum buffer size is 4096. The default buffers size can be set using
* wl_display_set_default_max_buffer_size().
*
* \sa wl_display_set_default_max_buffer_size()
*
* \memberof wl_client
* \since 1.22.90
*/
WL_EXPORT void
wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size)
{
if (max_buffer_size < WL_BUFFER_DEFAULT_MAX_SIZE)
max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE;
wl_connection_set_max_buffer_size(client->connection, max_buffer_size);
}
/** \cond INTERNAL */
/** Initialize a wl_priv_signal object
@ -2382,9 +2570,10 @@ wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data)
/** \cond */ /* Deprecated functions below. */
WL_DEPRECATED
uint32_t
wl_client_add_resource(struct wl_client *client,
struct wl_resource *resource) WL_DEPRECATED;
struct wl_resource *resource);
WL_EXPORT uint32_t
wl_client_add_resource(struct wl_client *client,
@ -2413,11 +2602,12 @@ wl_client_add_resource(struct wl_client *client,
return resource->object.id;
}
WL_DEPRECATED
struct wl_resource *
wl_client_add_object(struct wl_client *client,
const struct wl_interface *interface,
const void *implementation,
uint32_t id, void *data) WL_DEPRECATED;
uint32_t id, void *data);
WL_EXPORT struct wl_resource *
wl_client_add_object(struct wl_client *client,
@ -2436,10 +2626,11 @@ wl_client_add_object(struct wl_client *client,
return resource;
}
WL_DEPRECATED
struct wl_resource *
wl_client_new_object(struct wl_client *client,
const struct wl_interface *interface,
const void *implementation, void *data) WL_DEPRECATED;
const void *implementation, void *data);
WL_EXPORT struct wl_resource *
wl_client_new_object(struct wl_client *client,
@ -2458,10 +2649,51 @@ wl_client_new_object(struct wl_client *client,
return resource;
}
/** Set the client's user data
*
* User data is whatever the caller wants to store. Use dtor if
* the user data needs freeing as the very last step of destroying
* the client.
*
* \param client The client object
* \param data The user data pointer
* \param dtor Destroy function to be called after all resources have been
* destroyed and all destroy listeners have been called. Can be NULL.
*
* The argument to the destroy function is the user data pointer. If the
* destroy function is not NULL, it will be called even if user data is NULL.
*
* \since 1.22.90
* \sa wl_client_get_user_data
*/
WL_EXPORT void
wl_client_set_user_data(struct wl_client *client,
void *data,
wl_user_data_destroy_func_t dtor)
{
client->data = data;
client->data_dtor = dtor;
}
/** Get the client's user data
*
* \param client The client object
* \return The user data pointer
*
* \since 1.22.90
* \sa wl_client_set_user_data
*/
WL_EXPORT void *
wl_client_get_user_data(struct wl_client *client)
{
return client->data;
}
WL_DEPRECATED
struct wl_global *
wl_display_add_global(struct wl_display *display,
const struct wl_interface *interface,
void *data, wl_global_bind_func_t bind) WL_DEPRECATED;
void *data, wl_global_bind_func_t bind);
WL_EXPORT struct wl_global *
wl_display_add_global(struct wl_display *display,
@ -2471,9 +2703,10 @@ wl_display_add_global(struct wl_display *display,
return wl_global_create(display, interface, interface->version, data, bind);
}
WL_DEPRECATED
void
wl_display_remove_global(struct wl_display *display,
struct wl_global *global) WL_DEPRECATED;
struct wl_global *global);
WL_EXPORT void
wl_display_remove_global(struct wl_display *display, struct wl_global *global)

View file

@ -70,30 +70,35 @@ struct wl_resource {
void *data;
};
WL_DEPRECATED
uint32_t
wl_client_add_resource(struct wl_client *client,
struct wl_resource *resource) WL_DEPRECATED;
struct wl_resource *resource);
WL_DEPRECATED
struct wl_resource *
wl_client_add_object(struct wl_client *client,
const struct wl_interface *interface,
const void *implementation,
uint32_t id, void *data) WL_DEPRECATED;
uint32_t id, void *data);
WL_DEPRECATED
struct wl_resource *
wl_client_new_object(struct wl_client *client,
const struct wl_interface *interface,
const void *implementation, void *data) WL_DEPRECATED;
const void *implementation, void *data);
WL_DEPRECATED
struct wl_global *
wl_display_add_global(struct wl_display *display,
const struct wl_interface *interface,
void *data,
wl_global_bind_func_t bind) WL_DEPRECATED;
wl_global_bind_func_t bind);
WL_DEPRECATED
void
wl_display_remove_global(struct wl_display *display,
struct wl_global *global) WL_DEPRECATED;
struct wl_global *global);
#endif

View file

@ -40,7 +40,6 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
@ -85,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;
@ -144,12 +147,16 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external)
{
if (external) {
pool->external_refcount--;
assert(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--;
assert(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)
@ -162,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
@ -202,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,
@ -234,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;
@ -310,6 +361,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource,
int seals;
int prot;
int flags;
uint32_t version;
if (size <= 0) {
wl_resource_post_error(resource,
@ -358,8 +410,10 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource,
#else
close(fd);
#endif
version = wl_resource_get_version(resource);
pool->resource =
wl_resource_create(client, &wl_shm_pool_interface, 1, id);
wl_resource_create(client, &wl_shm_pool_interface, version, id);
if (!pool->resource) {
wl_client_post_no_memory(client);
munmap(pool->data, pool->size);
@ -379,8 +433,15 @@ err_close:
close(fd);
}
static void
shm_release(struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static const struct wl_shm_interface shm_interface = {
shm_create_pool
shm_create_pool,
shm_release,
};
static void
@ -392,7 +453,7 @@ bind_shm(struct wl_client *client,
struct wl_array *additional_formats;
uint32_t *p;
resource = wl_resource_create(client, &wl_shm_interface, 1, id);
resource = wl_resource_create(client, &wl_shm_interface, version, id);
if (!resource) {
wl_client_post_no_memory(client);
return;
@ -411,7 +472,7 @@ bind_shm(struct wl_client *client,
WL_EXPORT int
wl_display_init_shm(struct wl_display *display)
{
if (!wl_global_create(display, &wl_shm_interface, 1, NULL, bind_shm))
if (!wl_global_create(display, &wl_shm_interface, 2, NULL, bind_shm))
return -1;
return 0;
@ -431,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;
}
@ -448,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
*/
@ -465,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
@ -489,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.
*
@ -499,9 +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)
{
assert(buffer->pool->internal_refcount +
buffer->pool->external_refcount);
buffer->pool->external_refcount++;
return buffer->pool;
}
@ -603,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.
*
@ -614,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.
*
@ -648,18 +745,19 @@ wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer)
pthread_setspecific(wl_shm_sigbus_data_key, sigbus_data);
}
assert(sigbus_data->current_pool == NULL ||
sigbus_data->current_pool == pool);
if (!(sigbus_data->current_pool == NULL ||
sigbus_data->current_pool == pool))
wl_abort("Incorrect pool passed for current thread\n");
sigbus_data->current_pool = pool;
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.
@ -676,13 +774,22 @@ wl_shm_buffer_end_access(struct wl_shm_buffer *buffer)
return;
sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key);
assert(sigbus_data && sigbus_data->access_count >= 1);
if (!(sigbus_data && sigbus_data->access_count >= 1))
wl_abort("sigbus_data is NULL or wl_shm_buffer_begin_access "
"wasn't called before\n");
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;
}

View file

@ -174,9 +174,23 @@ union map_entry {
void *data;
};
#define map_entry_is_free(entry) ((entry).next & 0x1)
#define map_entry_get_data(entry) ((void *)((entry).next & ~(uintptr_t)0x3))
#define map_entry_get_flags(entry) (((entry).next >> 1) & 0x1)
static inline bool
map_entry_is_free(union map_entry entry)
{
return entry.next & 0x1;
}
static inline void *
map_entry_get_data(union map_entry entry)
{
return (void *)(entry.next & ~(uintptr_t)0x3);
}
static inline uint32_t
map_entry_get_flags(union map_entry entry)
{
return (entry.next >> 1) & 0x1;
}
void
wl_map_init(struct wl_map *map, uint32_t side)

View file

@ -48,7 +48,9 @@ extern "C" {
#endif
/** Deprecated attribute */
#if defined(__GNUC__) && __GNUC__ >= 4
#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))
#else
#define WL_DEPRECATED
@ -68,6 +70,12 @@ extern "C" {
#define WL_PRINTF(x, y)
#endif
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
#define WL_TYPEOF(expr) typeof(expr)
#else
#define WL_TYPEOF(expr) __typeof__(expr)
#endif
/** \class wl_object
*
* \brief A protocol object.
@ -82,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
*
@ -406,8 +422,8 @@ wl_list_insert_list(struct wl_list *list, struct wl_list *other);
* \return The container for the specified pointer
*/
#define wl_container_of(ptr, sample, member) \
(__typeof__(sample))((char *)(ptr) - \
offsetof(__typeof__(*sample), member))
(WL_TYPEOF(sample))((char *)(ptr) - \
offsetof(WL_TYPEOF(*sample), member))
/**
* Iterates over a list.
@ -590,6 +606,7 @@ wl_array_copy(struct wl_array *array, struct wl_array *source);
*/
#define wl_array_for_each(pos, array) \
for (pos = (array)->data; \
(array)->size != 0 && \
(const char *) pos < ((const char *) (array)->data + (array)->size); \
(pos)++)
@ -613,14 +630,7 @@ typedef int32_t wl_fixed_t;
static inline double
wl_fixed_to_double(wl_fixed_t f)
{
union {
double d;
int64_t i;
} u;
u.i = ((1023LL + 44LL) << 52) + (1LL << 51) + f;
return u.d - (3LL << 43);
return f / 256.0;
}
/**
@ -633,14 +643,7 @@ wl_fixed_to_double(wl_fixed_t f)
static inline wl_fixed_t
wl_fixed_from_double(double d)
{
union {
double d;
int64_t i;
} u;
u.d = d + (3LL << (51 - 8));
return (wl_fixed_t)u.i;
return (wl_fixed_t) (round(d * 256.0));
}
/**

View file

@ -80,12 +80,21 @@ client_late_destroy_notify(struct wl_listener *l, void *data)
listener->late_done = true;
}
static void
client_user_data_destroy(void *data)
{
bool *user_data_destroyed = data;
*user_data_destroyed = true;
}
TEST(client_destroy_listener)
{
struct wl_display *display;
struct wl_client *client;
struct wl_resource *resource;
struct client_destroy_listener a, b;
bool user_data_destroyed = false;
int s[2];
assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
@ -94,6 +103,9 @@ TEST(client_destroy_listener)
client = wl_client_create(display, s[0]);
assert(client);
wl_client_set_user_data(client, &user_data_destroyed, client_user_data_destroy);
assert(wl_client_get_user_data(client) == &user_data_destroyed);
resource = wl_resource_create(client, &wl_callback_interface, 1, 0);
assert(resource);
@ -128,6 +140,8 @@ TEST(client_destroy_listener)
wl_list_remove(&a.resource_listener.link);
wl_list_remove(&a.late_listener.link);
assert(!user_data_destroyed);
wl_client_destroy(client);
assert(!a.done);
@ -136,6 +150,7 @@ TEST(client_destroy_listener)
assert(b.done);
assert(b.resource_done);
assert(b.late_done);
assert(user_data_destroyed);
close(s[0]);
close(s[1]);
@ -143,3 +158,50 @@ TEST(client_destroy_listener)
wl_display_destroy(display);
}
static void
client_destroy_remove_link_notify(struct wl_listener *l, void *data)
{
struct wl_client *client = data;
struct client_destroy_listener *listener =
wl_container_of(l, listener, listener);
/* The client destruction signal should not be emitted more than once. */
assert(!listener->done);
listener->done = true;
/* The client should have been removed from the display's list. */
assert(wl_list_empty(wl_client_get_link(client)));
}
/*
* Tests that wl_client_destroy() will remove the client from the display's
* client list to prevent client access during destruction.
*/
TEST(client_destroy_removes_link)
{
struct wl_display *display;
struct wl_client *client;
struct client_destroy_listener destroy_listener;
int s[2];
assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
display = wl_display_create();
assert(display);
client = wl_client_create(display, s[0]);
assert(client);
destroy_listener.listener.notify = client_destroy_remove_link_notify;
destroy_listener.done = false;
wl_client_add_destroy_listener(client, &destroy_listener.listener);
assert(wl_client_get_destroy_listener(client,
client_destroy_remove_link_notify) == &destroy_listener.listener);
wl_client_destroy(client);
assert(destroy_listener.done);
close(s[0]);
close(s[1]);
wl_display_destroy(display);
}

View file

@ -50,7 +50,7 @@ setup(int *s)
assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
connection = wl_connection_create(s[0]);
connection = wl_connection_create(s[0], WL_BUFFER_DEFAULT_MAX_SIZE);
assert(connection);
return connection;
@ -183,9 +183,11 @@ setup_marshal_data(struct marshal_data *data)
{
assert(socketpair(AF_UNIX,
SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
data->read_connection = wl_connection_create(data->s[0]);
data->read_connection = wl_connection_create(data->s[0],
WL_BUFFER_DEFAULT_MAX_SIZE);
assert(data->read_connection);
data->write_connection = wl_connection_create(data->s[1]);
data->write_connection = wl_connection_create(data->s[1],
WL_BUFFER_DEFAULT_MAX_SIZE);
assert(data->write_connection);
}
@ -277,6 +279,25 @@ expected_fail_marshal(int expected_error, const char *format, ...)
assert(errno == expected_error);
}
static void
marshal_send(struct marshal_data *data, const char *format, ...)
{
struct wl_closure *closure;
static const uint32_t opcode = 4444;
static struct wl_object sender = { NULL, NULL, 1234 };
struct wl_message message = { "test", format, NULL };
va_list ap;
va_start(ap, format);
closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
va_end(ap);
assert(closure);
assert(wl_closure_send(closure, data->write_connection) == 0);
wl_closure_destroy(closure);
}
static void
expected_fail_marshal_send(struct marshal_data *data, int expected_error,
const char *format, ...)
@ -644,6 +665,46 @@ TEST(connection_marshal_too_big)
free(big_string);
}
TEST(connection_marshal_big_enough)
{
struct marshal_data data;
char *big_string = malloc(5000);
assert(big_string);
memset(big_string, ' ', 4999);
big_string[4999] = '\0';
setup_marshal_data(&data);
wl_connection_set_max_buffer_size(data.write_connection, 5120);
marshal_send(&data, "s", big_string);
release_marshal_data(&data);
free(big_string);
}
TEST(connection_marshal_unbounded_boundary_size)
{
/* 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);
memset(big_string, ' ', 8177);
big_string[8177] = '\0';
setup_marshal_data(&data);
/* Set the max size to 0 (unbounded). */
wl_connection_set_max_buffer_size(data.write_connection, 0);
marshal_send(&data, "s", big_string);
release_marshal_data(&data);
free(big_string);
}
static void
marshal_helper(const char *format, void *handler, ...)
{

3
tests/data/README.md Normal file
View file

@ -0,0 +1,3 @@
To re-generate the test data, run:
ninja -C build/ gen-scanner-test

83
tests/data/empty-client.h Normal file
View file

@ -0,0 +1,83 @@
/* SCANNER TEST */
#ifndef EMPTY_CLIENT_PROTOCOL_H
#define EMPTY_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_empty The empty protocol
* @section page_ifaces_empty Interfaces
* - @subpage page_iface_empty -
*/
struct empty;
#ifndef EMPTY_INTERFACE
#define EMPTY_INTERFACE
/**
* @page page_iface_empty empty
* @section page_iface_empty_api API
* See @ref iface_empty.
*/
/**
* @defgroup iface_empty The empty interface
*/
extern const struct wl_interface empty_interface;
#endif
#define EMPTY_EMPTY 0
/**
* @ingroup iface_empty
*/
#define EMPTY_EMPTY_SINCE_VERSION 1
/** @ingroup iface_empty */
static inline void
empty_set_user_data(struct empty *empty, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) empty, user_data);
}
/** @ingroup iface_empty */
static inline void *
empty_get_user_data(struct empty *empty)
{
return wl_proxy_get_user_data((struct wl_proxy *) empty);
}
static inline uint32_t
empty_get_version(struct empty *empty)
{
return wl_proxy_get_version((struct wl_proxy *) empty);
}
/** @ingroup iface_empty */
static inline void
empty_destroy(struct empty *empty)
{
wl_proxy_destroy((struct wl_proxy *) empty);
}
/**
* @ingroup iface_empty
*/
static inline void
empty_empty(struct empty *empty)
{
wl_proxy_marshal_flags((struct wl_proxy *) empty,
EMPTY_EMPTY, NULL, wl_proxy_get_version((struct wl_proxy *) empty), 0);
}
#ifdef __cplusplus
}
#endif
#endif

21
tests/data/empty-code.c Normal file
View file

@ -0,0 +1,21 @@
/* SCANNER TEST */
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
static const struct wl_interface *empty_types[] = {
};
static const struct wl_message empty_requests[] = {
{ "empty", "", empty_types + 0 },
};
WL_EXPORT const struct wl_interface empty_interface = {
"empty", 1,
1, empty_requests,
0, NULL,
};

58
tests/data/empty-server.h Normal file
View file

@ -0,0 +1,58 @@
/* SCANNER TEST */
#ifndef EMPTY_SERVER_PROTOCOL_H
#define EMPTY_SERVER_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-server.h"
#ifdef __cplusplus
extern "C" {
#endif
struct wl_client;
struct wl_resource;
/**
* @page page_empty The empty protocol
* @section page_ifaces_empty Interfaces
* - @subpage page_iface_empty -
*/
struct empty;
#ifndef EMPTY_INTERFACE
#define EMPTY_INTERFACE
/**
* @page page_iface_empty empty
* @section page_iface_empty_api API
* See @ref iface_empty.
*/
/**
* @defgroup iface_empty The empty interface
*/
extern const struct wl_interface empty_interface;
#endif
/**
* @ingroup iface_empty
* @struct empty_interface
*/
struct empty_interface {
/**
*/
void (*empty)(struct wl_client *client,
struct wl_resource *resource);
};
/**
* @ingroup iface_empty
*/
#define EMPTY_EMPTY_SINCE_VERSION 1
#ifdef __cplusplus
}
#endif
#endif

7
tests/data/empty.xml Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="empty">
<interface name="empty" version="1">
<request name="empty">
</request>
</interface>
</protocol>

View file

@ -27,6 +27,7 @@
* SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"

836
tests/data/example-enum.h Normal file
View file

@ -0,0 +1,836 @@
/* SCANNER TEST */
#ifndef WAYLAND_ENUM_PROTOCOL_H
#define WAYLAND_ENUM_PROTOCOL_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WL_DISPLAY_ERROR_ENUM
#define WL_DISPLAY_ERROR_ENUM
/**
* @ingroup iface_wl_display
* global error values
*
* These errors are global and can be emitted in response to any
* server request.
*/
enum wl_display_error {
/**
* server couldn't find object
*/
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
/**
* method doesn't exist on the specified interface
*/
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
/**
* server is out of memory
*/
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
#endif /* WL_DISPLAY_ERROR_ENUM */
#ifndef WL_SHM_ERROR_ENUM
#define WL_SHM_ERROR_ENUM
/**
* @ingroup iface_wl_shm
* wl_shm error values
*
* These errors can be emitted in response to wl_shm requests.
*/
enum wl_shm_error {
/**
* buffer format is not known
*/
WL_SHM_ERROR_INVALID_FORMAT = 0,
/**
* invalid size or stride during pool or buffer creation
*/
WL_SHM_ERROR_INVALID_STRIDE = 1,
/**
* mmapping the file descriptor failed
*/
WL_SHM_ERROR_INVALID_FD = 2,
};
#endif /* WL_SHM_ERROR_ENUM */
#ifndef WL_SHM_FORMAT_ENUM
#define WL_SHM_FORMAT_ENUM
/**
* @ingroup iface_wl_shm
* pixel formats
*
* This describes the memory layout of an individual pixel.
*
* All renderers should support argb8888 and xrgb8888 but any other
* formats are optional and may not be supported by the particular
* renderer in use.
*
* The drm format codes match the macros defined in drm_fourcc.h.
* The formats actually supported by the compositor will be
* reported by the format event.
*/
enum wl_shm_format {
/**
* 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian
*/
WL_SHM_FORMAT_ARGB8888 = 0,
/**
* 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian
*/
WL_SHM_FORMAT_XRGB8888 = 1,
/**
* 8-bit color index format, [7:0] C
*/
WL_SHM_FORMAT_C8 = 0x20203843,
/**
* 8-bit RGB format, [7:0] R:G:B 3:3:2
*/
WL_SHM_FORMAT_RGB332 = 0x38424752,
/**
* 8-bit BGR format, [7:0] B:G:R 2:3:3
*/
WL_SHM_FORMAT_BGR233 = 0x38524742,
/**
* 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian
*/
WL_SHM_FORMAT_XRGB4444 = 0x32315258,
/**
* 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian
*/
WL_SHM_FORMAT_XBGR4444 = 0x32314258,
/**
* 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian
*/
WL_SHM_FORMAT_RGBX4444 = 0x32315852,
/**
* 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian
*/
WL_SHM_FORMAT_BGRX4444 = 0x32315842,
/**
* 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian
*/
WL_SHM_FORMAT_ARGB4444 = 0x32315241,
/**
* 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian
*/
WL_SHM_FORMAT_ABGR4444 = 0x32314241,
/**
* 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian
*/
WL_SHM_FORMAT_RGBA4444 = 0x32314152,
/**
* 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian
*/
WL_SHM_FORMAT_BGRA4444 = 0x32314142,
/**
* 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian
*/
WL_SHM_FORMAT_XRGB1555 = 0x35315258,
/**
* 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian
*/
WL_SHM_FORMAT_XBGR1555 = 0x35314258,
/**
* 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian
*/
WL_SHM_FORMAT_RGBX5551 = 0x35315852,
/**
* 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian
*/
WL_SHM_FORMAT_BGRX5551 = 0x35315842,
/**
* 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian
*/
WL_SHM_FORMAT_ARGB1555 = 0x35315241,
/**
* 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian
*/
WL_SHM_FORMAT_ABGR1555 = 0x35314241,
/**
* 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian
*/
WL_SHM_FORMAT_RGBA5551 = 0x35314152,
/**
* 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian
*/
WL_SHM_FORMAT_BGRA5551 = 0x35314142,
/**
* 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian
*/
WL_SHM_FORMAT_RGB565 = 0x36314752,
/**
* 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian
*/
WL_SHM_FORMAT_BGR565 = 0x36314742,
/**
* 24-bit RGB format, [23:0] R:G:B little endian
*/
WL_SHM_FORMAT_RGB888 = 0x34324752,
/**
* 24-bit BGR format, [23:0] B:G:R little endian
*/
WL_SHM_FORMAT_BGR888 = 0x34324742,
/**
* 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian
*/
WL_SHM_FORMAT_XBGR8888 = 0x34324258,
/**
* 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian
*/
WL_SHM_FORMAT_RGBX8888 = 0x34325852,
/**
* 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian
*/
WL_SHM_FORMAT_BGRX8888 = 0x34325842,
/**
* 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian
*/
WL_SHM_FORMAT_ABGR8888 = 0x34324241,
/**
* 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian
*/
WL_SHM_FORMAT_RGBA8888 = 0x34324152,
/**
* 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian
*/
WL_SHM_FORMAT_BGRA8888 = 0x34324142,
/**
* 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian
*/
WL_SHM_FORMAT_XRGB2101010 = 0x30335258,
/**
* 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian
*/
WL_SHM_FORMAT_XBGR2101010 = 0x30334258,
/**
* 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian
*/
WL_SHM_FORMAT_RGBX1010102 = 0x30335852,
/**
* 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian
*/
WL_SHM_FORMAT_BGRX1010102 = 0x30335842,
/**
* 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian
*/
WL_SHM_FORMAT_ARGB2101010 = 0x30335241,
/**
* 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian
*/
WL_SHM_FORMAT_ABGR2101010 = 0x30334241,
/**
* 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian
*/
WL_SHM_FORMAT_RGBA1010102 = 0x30334152,
/**
* 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian
*/
WL_SHM_FORMAT_BGRA1010102 = 0x30334142,
/**
* packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian
*/
WL_SHM_FORMAT_YUYV = 0x56595559,
/**
* packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian
*/
WL_SHM_FORMAT_YVYU = 0x55595659,
/**
* packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian
*/
WL_SHM_FORMAT_UYVY = 0x59565955,
/**
* packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian
*/
WL_SHM_FORMAT_VYUY = 0x59555956,
/**
* packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian
*/
WL_SHM_FORMAT_AYUV = 0x56555941,
/**
* 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane
*/
WL_SHM_FORMAT_NV12 = 0x3231564e,
/**
* 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane
*/
WL_SHM_FORMAT_NV21 = 0x3132564e,
/**
* 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane
*/
WL_SHM_FORMAT_NV16 = 0x3631564e,
/**
* 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane
*/
WL_SHM_FORMAT_NV61 = 0x3136564e,
/**
* 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes
*/
WL_SHM_FORMAT_YUV410 = 0x39565559,
/**
* 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes
*/
WL_SHM_FORMAT_YVU410 = 0x39555659,
/**
* 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes
*/
WL_SHM_FORMAT_YUV411 = 0x31315559,
/**
* 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes
*/
WL_SHM_FORMAT_YVU411 = 0x31315659,
/**
* 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes
*/
WL_SHM_FORMAT_YUV420 = 0x32315559,
/**
* 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes
*/
WL_SHM_FORMAT_YVU420 = 0x32315659,
/**
* 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes
*/
WL_SHM_FORMAT_YUV422 = 0x36315559,
/**
* 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes
*/
WL_SHM_FORMAT_YVU422 = 0x36315659,
/**
* 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes
*/
WL_SHM_FORMAT_YUV444 = 0x34325559,
/**
* 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes
*/
WL_SHM_FORMAT_YVU444 = 0x34325659,
};
#endif /* WL_SHM_FORMAT_ENUM */
#ifndef WL_DATA_OFFER_ERROR_ENUM
#define WL_DATA_OFFER_ERROR_ENUM
enum wl_data_offer_error {
/**
* finish request was called untimely
*/
WL_DATA_OFFER_ERROR_INVALID_FINISH = 0,
/**
* action mask contains invalid values
*/
WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1,
/**
* action argument has an invalid value
*/
WL_DATA_OFFER_ERROR_INVALID_ACTION = 2,
/**
* offer doesn't accept this request
*/
WL_DATA_OFFER_ERROR_INVALID_OFFER = 3,
};
#endif /* WL_DATA_OFFER_ERROR_ENUM */
#ifndef WL_DATA_SOURCE_ERROR_ENUM
#define WL_DATA_SOURCE_ERROR_ENUM
enum wl_data_source_error {
/**
* action mask contains invalid values
*/
WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0,
/**
* source doesn't accept this request
*/
WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1,
};
#endif /* WL_DATA_SOURCE_ERROR_ENUM */
#ifndef WL_DATA_DEVICE_ERROR_ENUM
#define WL_DATA_DEVICE_ERROR_ENUM
enum wl_data_device_error {
/**
* given wl_surface has another role
*/
WL_DATA_DEVICE_ERROR_ROLE = 0,
};
#endif /* WL_DATA_DEVICE_ERROR_ENUM */
#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
/**
* @ingroup iface_wl_data_device_manager
* drag and drop actions
*
* This is a bitmask of the available/preferred actions in a
* drag-and-drop operation.
*
* In the compositor, the selected action is a result of matching the
* actions offered by the source and destination sides. "action" events
* with a "none" action will be sent to both source and destination if
* there is no match. All further checks will effectively happen on
* (source actions destination actions).
*
* In addition, compositors may also pick different actions in
* reaction to key modifiers being pressed. One common design that
* is used in major toolkits (and the behavior recommended for
* compositors) is:
*
* - If no modifiers are pressed, the first match (in bit order)
* will be used.
* - Pressing Shift selects "move", if enabled in the mask.
* - Pressing Control selects "copy", if enabled in the mask.
*
* Behavior beyond that is considered implementation-dependent.
* Compositors may for example bind other modifiers (like Alt/Meta)
* or drags initiated with other buttons than BTN_LEFT to specific
* actions (e.g. "ask").
*/
enum wl_data_device_manager_dnd_action {
/**
* no action
*/
WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0,
/**
* copy action
*/
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1,
/**
* move action
*/
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2,
/**
* ask action
*/
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4,
};
#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */
#ifndef WL_SHELL_ERROR_ENUM
#define WL_SHELL_ERROR_ENUM
enum wl_shell_error {
/**
* given wl_surface has another role
*/
WL_SHELL_ERROR_ROLE = 0,
};
#endif /* WL_SHELL_ERROR_ENUM */
#ifndef WL_SHELL_SURFACE_RESIZE_ENUM
#define WL_SHELL_SURFACE_RESIZE_ENUM
/**
* @ingroup iface_wl_shell_surface
* edge values for resizing
*
* These values are used to indicate which edge of a surface
* is being dragged in a resize operation. The server may
* use this information to adapt its behavior, e.g. choose
* an appropriate cursor image.
*/
enum wl_shell_surface_resize {
/**
* no edge
*/
WL_SHELL_SURFACE_RESIZE_NONE = 0,
/**
* top edge
*/
WL_SHELL_SURFACE_RESIZE_TOP = 1,
/**
* bottom edge
*/
WL_SHELL_SURFACE_RESIZE_BOTTOM = 2,
/**
* left edge
*/
WL_SHELL_SURFACE_RESIZE_LEFT = 4,
/**
* top and left edges
*/
WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5,
/**
* bottom and left edges
*/
WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6,
/**
* right edge
*/
WL_SHELL_SURFACE_RESIZE_RIGHT = 8,
/**
* top and right edges
*/
WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9,
/**
* bottom and right edges
*/
WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10,
};
#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
#define WL_SHELL_SURFACE_TRANSIENT_ENUM
/**
* @ingroup iface_wl_shell_surface
* details of transient behaviour
*
* These flags specify details of the expected behaviour
* of transient surfaces. Used in the set_transient request.
*/
enum wl_shell_surface_transient {
/**
* do not set keyboard focus
*/
WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1,
};
#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
/**
* @ingroup iface_wl_shell_surface
* different method to set the surface fullscreen
*
* Hints to indicate to the compositor how to deal with a conflict
* between the dimensions of the surface and the dimensions of the
* output. The compositor is free to ignore this parameter.
*/
enum wl_shell_surface_fullscreen_method {
/**
* no preference, apply default policy
*/
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0,
/**
* scale, preserve the surface's aspect ratio and center on output
*/
WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1,
/**
* switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch
*/
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2,
/**
* no upscaling, center on output and add black borders to compensate size mismatch
*/
WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3,
};
#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
#ifndef WL_SURFACE_ERROR_ENUM
#define WL_SURFACE_ERROR_ENUM
/**
* @ingroup iface_wl_surface
* wl_surface error values
*
* These errors can be emitted in response to wl_surface requests.
*/
enum wl_surface_error {
/**
* buffer scale value is invalid
*/
WL_SURFACE_ERROR_INVALID_SCALE = 0,
/**
* buffer transform value is invalid
*/
WL_SURFACE_ERROR_INVALID_TRANSFORM = 1,
};
#endif /* WL_SURFACE_ERROR_ENUM */
#ifndef WL_SEAT_CAPABILITY_ENUM
#define WL_SEAT_CAPABILITY_ENUM
/**
* @ingroup iface_wl_seat
* seat capability bitmask
*
* This is a bitmask of capabilities this seat has; if a member is
* set, then it is present on the seat.
*/
enum wl_seat_capability {
/**
* the seat has pointer devices
*/
WL_SEAT_CAPABILITY_POINTER = 1,
/**
* the seat has one or more keyboards
*/
WL_SEAT_CAPABILITY_KEYBOARD = 2,
/**
* the seat has touch devices
*/
WL_SEAT_CAPABILITY_TOUCH = 4,
};
#endif /* WL_SEAT_CAPABILITY_ENUM */
#ifndef WL_POINTER_ERROR_ENUM
#define WL_POINTER_ERROR_ENUM
enum wl_pointer_error {
/**
* given wl_surface has another role
*/
WL_POINTER_ERROR_ROLE = 0,
};
#endif /* WL_POINTER_ERROR_ENUM */
#ifndef WL_POINTER_BUTTON_STATE_ENUM
#define WL_POINTER_BUTTON_STATE_ENUM
/**
* @ingroup iface_wl_pointer
* physical button state
*
* Describes the physical state of a button that produced the button
* event.
*/
enum wl_pointer_button_state {
/**
* the button is not pressed
*/
WL_POINTER_BUTTON_STATE_RELEASED = 0,
/**
* the button is pressed
*/
WL_POINTER_BUTTON_STATE_PRESSED = 1,
};
#endif /* WL_POINTER_BUTTON_STATE_ENUM */
#ifndef WL_POINTER_AXIS_ENUM
#define WL_POINTER_AXIS_ENUM
/**
* @ingroup iface_wl_pointer
* axis types
*
* Describes the axis types of scroll events.
*/
enum wl_pointer_axis {
/**
* vertical axis
*/
WL_POINTER_AXIS_VERTICAL_SCROLL = 0,
/**
* horizontal axis
*/
WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
};
#endif /* WL_POINTER_AXIS_ENUM */
#ifndef WL_POINTER_AXIS_SOURCE_ENUM
#define WL_POINTER_AXIS_SOURCE_ENUM
/**
* @ingroup iface_wl_pointer
* axis source types
*
* Describes the source types for axis events. This indicates to the
* client how an axis event was physically generated; a client may
* adjust the user interface accordingly. For example, scroll events
* from a "finger" source may be in a smooth coordinate space with
* kinetic scrolling whereas a "wheel" source may be in discrete steps
* of a number of lines.
*/
enum wl_pointer_axis_source {
/**
* a physical wheel rotation
*/
WL_POINTER_AXIS_SOURCE_WHEEL = 0,
/**
* finger on a touch surface
*/
WL_POINTER_AXIS_SOURCE_FINGER = 1,
/**
* continuous coordinate space
*
* A device generating events in a continuous coordinate space,
* but using something other than a finger. One example for this
* source is button-based scrolling where the vertical motion of a
* device is converted to scroll events while a button is held
* down.
*/
WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2,
/**
* a physical wheel tilt
*
* Indicates that the actual device is a wheel but the scroll
* event is not caused by a rotation but a (usually sideways) tilt
* of the wheel.
* @since 6
*/
WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3,
};
/**
* @ingroup iface_wl_pointer
*/
#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6
#endif /* WL_POINTER_AXIS_SOURCE_ENUM */
#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM
#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM
/**
* @ingroup iface_wl_keyboard
* keyboard mapping format
*
* This specifies the format of the keymap provided to the
* client with the wl_keyboard.keymap event.
*/
enum wl_keyboard_keymap_format {
/**
* no keymap; client must understand how to interpret the raw keycode
*/
WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0,
/**
* libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode
*/
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1,
};
#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
#ifndef WL_KEYBOARD_KEY_STATE_ENUM
#define WL_KEYBOARD_KEY_STATE_ENUM
/**
* @ingroup iface_wl_keyboard
* physical key state
*
* Describes the physical state of a key that produced the key event.
*/
enum wl_keyboard_key_state {
/**
* key is not pressed
*/
WL_KEYBOARD_KEY_STATE_RELEASED = 0,
/**
* key is pressed
*/
WL_KEYBOARD_KEY_STATE_PRESSED = 1,
};
#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
#ifndef WL_OUTPUT_SUBPIXEL_ENUM
#define WL_OUTPUT_SUBPIXEL_ENUM
/**
* @ingroup iface_wl_output
* subpixel geometry information
*
* This enumeration describes how the physical
* pixels on an output are laid out.
*/
enum wl_output_subpixel {
/**
* unknown geometry
*/
WL_OUTPUT_SUBPIXEL_UNKNOWN = 0,
/**
* no geometry
*/
WL_OUTPUT_SUBPIXEL_NONE = 1,
/**
* horizontal RGB
*/
WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2,
/**
* horizontal BGR
*/
WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3,
/**
* vertical RGB
*/
WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4,
/**
* vertical BGR
*/
WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5,
};
#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
#ifndef WL_OUTPUT_TRANSFORM_ENUM
#define WL_OUTPUT_TRANSFORM_ENUM
/**
* @ingroup iface_wl_output
* transform from framebuffer to output
*
* This describes the transform that a compositor will apply to a
* surface to compensate for the rotation or mirroring of an
* output device.
*
* The flipped values correspond to an initial flip around a
* vertical axis followed by rotation.
*
* The purpose is mainly to allow clients to render accordingly and
* tell the compositor, so that for fullscreen surfaces, the
* compositor will still be able to scan out directly from client
* surfaces.
*/
enum wl_output_transform {
/**
* no transform
*/
WL_OUTPUT_TRANSFORM_NORMAL = 0,
/**
* 90 degrees counter-clockwise
*/
WL_OUTPUT_TRANSFORM_90 = 1,
/**
* 180 degrees counter-clockwise
*/
WL_OUTPUT_TRANSFORM_180 = 2,
/**
* 270 degrees counter-clockwise
*/
WL_OUTPUT_TRANSFORM_270 = 3,
/**
* 180 degree flip around a vertical axis
*/
WL_OUTPUT_TRANSFORM_FLIPPED = 4,
/**
* flip and rotate 90 degrees counter-clockwise
*/
WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5,
/**
* flip and rotate 180 degrees counter-clockwise
*/
WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6,
/**
* flip and rotate 270 degrees counter-clockwise
*/
WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7,
};
#endif /* WL_OUTPUT_TRANSFORM_ENUM */
#ifndef WL_OUTPUT_MODE_ENUM
#define WL_OUTPUT_MODE_ENUM
/**
* @ingroup iface_wl_output
* mode information
*
* These flags describe properties of an output mode.
* They are used in the flags bitfield of the mode event.
*/
enum wl_output_mode {
/**
* indicates this is the current mode
*/
WL_OUTPUT_MODE_CURRENT = 0x1,
/**
* indicates this is the preferred mode
*/
WL_OUTPUT_MODE_PREFERRED = 0x2,
};
#endif /* WL_OUTPUT_MODE_ENUM */
#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM
#define WL_SUBCOMPOSITOR_ERROR_ENUM
enum wl_subcompositor_error {
/**
* the to-be sub-surface is invalid
*/
WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0,
};
#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
#ifndef WL_SUBSURFACE_ERROR_ENUM
#define WL_SUBSURFACE_ERROR_ENUM
enum wl_subsurface_error {
/**
* wl_surface is not a sibling or the parent
*/
WL_SUBSURFACE_ERROR_BAD_SURFACE = 0,
};
#endif /* WL_SUBSURFACE_ERROR_ENUM */
#ifdef __cplusplus
}
#endif
#endif

View file

@ -903,6 +903,30 @@ enum wl_display_error {
};
#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.
*
* @return true on success, false on error.
* @ref wl_display_error
*/
static inline bool
wl_display_error_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_DISPLAY_ERROR_INVALID_OBJECT:
return version >= 1;
case WL_DISPLAY_ERROR_INVALID_METHOD:
return version >= 1;
case WL_DISPLAY_ERROR_NO_MEMORY:
return version >= 1;
default:
return false;
}
}
#endif /* WL_DISPLAY_ERROR_ENUM_IS_VALID */
/**
* @ingroup iface_wl_display
* @struct wl_display_interface
@ -1176,6 +1200,30 @@ enum wl_shm_error {
};
#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.
*
* @return true on success, false on error.
* @ref wl_shm_error
*/
static inline bool
wl_shm_error_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_SHM_ERROR_INVALID_FORMAT:
return version >= 1;
case WL_SHM_ERROR_INVALID_STRIDE:
return version >= 1;
case WL_SHM_ERROR_INVALID_FD:
return version >= 1;
default:
return false;
}
}
#endif /* WL_SHM_ERROR_ENUM_IS_VALID */
#ifndef WL_SHM_FORMAT_ENUM
#define WL_SHM_FORMAT_ENUM
/**
@ -1428,6 +1476,140 @@ enum wl_shm_format {
};
#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.
*
* @return true on success, false on error.
* @ref wl_shm_format
*/
static inline bool
wl_shm_format_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_SHM_FORMAT_ARGB8888:
return version >= 1;
case WL_SHM_FORMAT_XRGB8888:
return version >= 1;
case WL_SHM_FORMAT_C8:
return version >= 1;
case WL_SHM_FORMAT_RGB332:
return version >= 1;
case WL_SHM_FORMAT_BGR233:
return version >= 1;
case WL_SHM_FORMAT_XRGB4444:
return version >= 1;
case WL_SHM_FORMAT_XBGR4444:
return version >= 1;
case WL_SHM_FORMAT_RGBX4444:
return version >= 1;
case WL_SHM_FORMAT_BGRX4444:
return version >= 1;
case WL_SHM_FORMAT_ARGB4444:
return version >= 1;
case WL_SHM_FORMAT_ABGR4444:
return version >= 1;
case WL_SHM_FORMAT_RGBA4444:
return version >= 1;
case WL_SHM_FORMAT_BGRA4444:
return version >= 1;
case WL_SHM_FORMAT_XRGB1555:
return version >= 1;
case WL_SHM_FORMAT_XBGR1555:
return version >= 1;
case WL_SHM_FORMAT_RGBX5551:
return version >= 1;
case WL_SHM_FORMAT_BGRX5551:
return version >= 1;
case WL_SHM_FORMAT_ARGB1555:
return version >= 1;
case WL_SHM_FORMAT_ABGR1555:
return version >= 1;
case WL_SHM_FORMAT_RGBA5551:
return version >= 1;
case WL_SHM_FORMAT_BGRA5551:
return version >= 1;
case WL_SHM_FORMAT_RGB565:
return version >= 1;
case WL_SHM_FORMAT_BGR565:
return version >= 1;
case WL_SHM_FORMAT_RGB888:
return version >= 1;
case WL_SHM_FORMAT_BGR888:
return version >= 1;
case WL_SHM_FORMAT_XBGR8888:
return version >= 1;
case WL_SHM_FORMAT_RGBX8888:
return version >= 1;
case WL_SHM_FORMAT_BGRX8888:
return version >= 1;
case WL_SHM_FORMAT_ABGR8888:
return version >= 1;
case WL_SHM_FORMAT_RGBA8888:
return version >= 1;
case WL_SHM_FORMAT_BGRA8888:
return version >= 1;
case WL_SHM_FORMAT_XRGB2101010:
return version >= 1;
case WL_SHM_FORMAT_XBGR2101010:
return version >= 1;
case WL_SHM_FORMAT_RGBX1010102:
return version >= 1;
case WL_SHM_FORMAT_BGRX1010102:
return version >= 1;
case WL_SHM_FORMAT_ARGB2101010:
return version >= 1;
case WL_SHM_FORMAT_ABGR2101010:
return version >= 1;
case WL_SHM_FORMAT_RGBA1010102:
return version >= 1;
case WL_SHM_FORMAT_BGRA1010102:
return version >= 1;
case WL_SHM_FORMAT_YUYV:
return version >= 1;
case WL_SHM_FORMAT_YVYU:
return version >= 1;
case WL_SHM_FORMAT_UYVY:
return version >= 1;
case WL_SHM_FORMAT_VYUY:
return version >= 1;
case WL_SHM_FORMAT_AYUV:
return version >= 1;
case WL_SHM_FORMAT_NV12:
return version >= 1;
case WL_SHM_FORMAT_NV21:
return version >= 1;
case WL_SHM_FORMAT_NV16:
return version >= 1;
case WL_SHM_FORMAT_NV61:
return version >= 1;
case WL_SHM_FORMAT_YUV410:
return version >= 1;
case WL_SHM_FORMAT_YVU410:
return version >= 1;
case WL_SHM_FORMAT_YUV411:
return version >= 1;
case WL_SHM_FORMAT_YVU411:
return version >= 1;
case WL_SHM_FORMAT_YUV420:
return version >= 1;
case WL_SHM_FORMAT_YVU420:
return version >= 1;
case WL_SHM_FORMAT_YUV422:
return version >= 1;
case WL_SHM_FORMAT_YVU422:
return version >= 1;
case WL_SHM_FORMAT_YUV444:
return version >= 1;
case WL_SHM_FORMAT_YVU444:
return version >= 1;
default:
return false;
}
}
#endif /* WL_SHM_FORMAT_ENUM_IS_VALID */
/**
* @ingroup iface_wl_shm
* @struct wl_shm_interface
@ -1538,6 +1720,32 @@ enum wl_data_offer_error {
};
#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.
*
* @return true on success, false on error.
* @ref wl_data_offer_error
*/
static inline bool
wl_data_offer_error_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_DATA_OFFER_ERROR_INVALID_FINISH:
return version >= 1;
case WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK:
return version >= 1;
case WL_DATA_OFFER_ERROR_INVALID_ACTION:
return version >= 1;
case WL_DATA_OFFER_ERROR_INVALID_OFFER:
return version >= 1;
default:
return false;
}
}
#endif /* WL_DATA_OFFER_ERROR_ENUM_IS_VALID */
/**
* @ingroup iface_wl_data_offer
* @struct wl_data_offer_interface
@ -1750,6 +1958,28 @@ enum wl_data_source_error {
};
#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.
*
* @return true on success, false on error.
* @ref wl_data_source_error
*/
static inline bool
wl_data_source_error_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK:
return version >= 1;
case WL_DATA_SOURCE_ERROR_INVALID_SOURCE:
return version >= 1;
default:
return false;
}
}
#endif /* WL_DATA_SOURCE_ERROR_ENUM_IS_VALID */
/**
* @ingroup iface_wl_data_source
* @struct wl_data_source_interface
@ -1922,6 +2152,26 @@ enum wl_data_device_error {
};
#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.
*
* @return true on success, false on error.
* @ref wl_data_device_error
*/
static inline bool
wl_data_device_error_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_DATA_DEVICE_ERROR_ROLE:
return version >= 1;
default:
return false;
}
}
#endif /* WL_DATA_DEVICE_ERROR_ENUM_IS_VALID */
/**
* @ingroup iface_wl_data_device
* @struct wl_data_device_interface
@ -2163,6 +2413,30 @@ enum wl_data_device_manager_dnd_action {
};
#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.
*
* @return true on success, false on error.
* @ref wl_data_device_manager_dnd_action
*/
static inline bool
wl_data_device_manager_dnd_action_is_valid(uint32_t value, uint32_t version) {
uint32_t valid = 0;
if (version >= 1)
valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
if (version >= 1)
valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
if (version >= 1)
valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
if (version >= 1)
valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
return (value & ~valid) == 0;
}
#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM_IS_VALID */
/**
* @ingroup iface_wl_data_device_manager
* @struct wl_data_device_manager_interface
@ -2210,6 +2484,26 @@ enum wl_shell_error {
};
#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.
*
* @return true on success, false on error.
* @ref wl_shell_error
*/
static inline bool
wl_shell_error_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_SHELL_ERROR_ROLE:
return version >= 1;
default:
return false;
}
}
#endif /* WL_SHELL_ERROR_ENUM_IS_VALID */
/**
* @ingroup iface_wl_shell
* @struct wl_shell_interface
@ -2289,6 +2583,40 @@ enum wl_shell_surface_resize {
};
#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.
*
* @return true on success, false on error.
* @ref wl_shell_surface_resize
*/
static inline bool
wl_shell_surface_resize_is_valid(uint32_t value, uint32_t version) {
uint32_t valid = 0;
if (version >= 1)
valid |= WL_SHELL_SURFACE_RESIZE_NONE;
if (version >= 1)
valid |= WL_SHELL_SURFACE_RESIZE_TOP;
if (version >= 1)
valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
if (version >= 1)
valid |= WL_SHELL_SURFACE_RESIZE_LEFT;
if (version >= 1)
valid |= WL_SHELL_SURFACE_RESIZE_TOP_LEFT;
if (version >= 1)
valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT;
if (version >= 1)
valid |= WL_SHELL_SURFACE_RESIZE_RIGHT;
if (version >= 1)
valid |= WL_SHELL_SURFACE_RESIZE_TOP_RIGHT;
if (version >= 1)
valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;
return (value & ~valid) == 0;
}
#endif /* WL_SHELL_SURFACE_RESIZE_ENUM_IS_VALID */
#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
#define WL_SHELL_SURFACE_TRANSIENT_ENUM
/**
@ -2306,6 +2634,24 @@ enum wl_shell_surface_transient {
};
#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.
*
* @return true on success, false on error.
* @ref wl_shell_surface_transient
*/
static inline bool
wl_shell_surface_transient_is_valid(uint32_t value, uint32_t version) {
uint32_t valid = 0;
if (version >= 1)
valid |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE;
return (value & ~valid) == 0;
}
#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM_IS_VALID */
#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
/**
@ -2336,6 +2682,32 @@ enum wl_shell_surface_fullscreen_method {
};
#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.
*
* @return true on success, false on error.
* @ref wl_shell_surface_fullscreen_method
*/
static inline bool
wl_shell_surface_fullscreen_method_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
return version >= 1;
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
return version >= 1;
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
return version >= 1;
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
return version >= 1;
default:
return false;
}
}
#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM_IS_VALID */
/**
* @ingroup iface_wl_shell_surface
* @struct wl_shell_surface_interface
@ -2668,6 +3040,28 @@ enum wl_surface_error {
};
#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.
*
* @return true on success, false on error.
* @ref wl_surface_error
*/
static inline bool
wl_surface_error_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_SURFACE_ERROR_INVALID_SCALE:
return version >= 1;
case WL_SURFACE_ERROR_INVALID_TRANSFORM:
return version >= 1;
default:
return false;
}
}
#endif /* WL_SURFACE_ERROR_ENUM_IS_VALID */
/**
* @ingroup iface_wl_surface
* @struct wl_surface_interface
@ -3127,6 +3521,28 @@ enum wl_seat_capability {
};
#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.
*
* @return true on success, false on error.
* @ref wl_seat_capability
*/
static inline bool
wl_seat_capability_is_valid(uint32_t value, uint32_t version) {
uint32_t valid = 0;
if (version >= 1)
valid |= WL_SEAT_CAPABILITY_POINTER;
if (version >= 1)
valid |= WL_SEAT_CAPABILITY_KEYBOARD;
if (version >= 1)
valid |= WL_SEAT_CAPABILITY_TOUCH;
return (value & ~valid) == 0;
}
#endif /* WL_SEAT_CAPABILITY_ENUM_IS_VALID */
/**
* @ingroup iface_wl_seat
* @struct wl_seat_interface
@ -3251,6 +3667,26 @@ enum wl_pointer_error {
};
#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.
*
* @return true on success, false on error.
* @ref wl_pointer_error
*/
static inline bool
wl_pointer_error_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_POINTER_ERROR_ROLE:
return version >= 1;
default:
return false;
}
}
#endif /* WL_POINTER_ERROR_ENUM_IS_VALID */
#ifndef WL_POINTER_BUTTON_STATE_ENUM
#define WL_POINTER_BUTTON_STATE_ENUM
/**
@ -3272,6 +3708,28 @@ enum wl_pointer_button_state {
};
#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.
*
* @return true on success, false on error.
* @ref wl_pointer_button_state
*/
static inline bool
wl_pointer_button_state_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_POINTER_BUTTON_STATE_RELEASED:
return version >= 1;
case WL_POINTER_BUTTON_STATE_PRESSED:
return version >= 1;
default:
return false;
}
}
#endif /* WL_POINTER_BUTTON_STATE_ENUM_IS_VALID */
#ifndef WL_POINTER_AXIS_ENUM
#define WL_POINTER_AXIS_ENUM
/**
@ -3292,6 +3750,28 @@ enum wl_pointer_axis {
};
#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.
*
* @return true on success, false on error.
* @ref wl_pointer_axis
*/
static inline bool
wl_pointer_axis_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_POINTER_AXIS_VERTICAL_SCROLL:
return version >= 1;
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
return version >= 1;
default:
return false;
}
}
#endif /* WL_POINTER_AXIS_ENUM_IS_VALID */
#ifndef WL_POINTER_AXIS_SOURCE_ENUM
#define WL_POINTER_AXIS_SOURCE_ENUM
/**
@ -3340,6 +3820,32 @@ enum wl_pointer_axis_source {
#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.
*
* @return true on success, false on error.
* @ref wl_pointer_axis_source
*/
static inline bool
wl_pointer_axis_source_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_POINTER_AXIS_SOURCE_WHEEL:
return version >= 1;
case WL_POINTER_AXIS_SOURCE_FINGER:
return version >= 1;
case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
return version >= 1;
case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
return version >= 6;
default:
return false;
}
}
#endif /* WL_POINTER_AXIS_SOURCE_ENUM_IS_VALID */
/**
* @ingroup iface_wl_pointer
* @struct wl_pointer_interface
@ -3601,6 +4107,28 @@ enum wl_keyboard_keymap_format {
};
#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.
*
* @return true on success, false on error.
* @ref wl_keyboard_keymap_format
*/
static inline bool
wl_keyboard_keymap_format_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP:
return version >= 1;
case WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1:
return version >= 1;
default:
return false;
}
}
#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM_IS_VALID */
#ifndef WL_KEYBOARD_KEY_STATE_ENUM
#define WL_KEYBOARD_KEY_STATE_ENUM
/**
@ -3621,6 +4149,28 @@ enum wl_keyboard_key_state {
};
#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.
*
* @return true on success, false on error.
* @ref wl_keyboard_key_state
*/
static inline bool
wl_keyboard_key_state_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_KEYBOARD_KEY_STATE_RELEASED:
return version >= 1;
case WL_KEYBOARD_KEY_STATE_PRESSED:
return version >= 1;
default:
return false;
}
}
#endif /* WL_KEYBOARD_KEY_STATE_ENUM_IS_VALID */
/**
* @ingroup iface_wl_keyboard
* @struct wl_keyboard_interface
@ -3947,6 +4497,36 @@ enum wl_output_subpixel {
};
#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.
*
* @return true on success, false on error.
* @ref wl_output_subpixel
*/
static inline bool
wl_output_subpixel_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_OUTPUT_SUBPIXEL_UNKNOWN:
return version >= 1;
case WL_OUTPUT_SUBPIXEL_NONE:
return version >= 1;
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
return version >= 1;
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
return version >= 1;
case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
return version >= 1;
case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
return version >= 1;
default:
return false;
}
}
#endif /* WL_OUTPUT_SUBPIXEL_ENUM_IS_VALID */
#ifndef WL_OUTPUT_TRANSFORM_ENUM
#define WL_OUTPUT_TRANSFORM_ENUM
/**
@ -4001,6 +4581,40 @@ enum wl_output_transform {
};
#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.
*
* @return true on success, false on error.
* @ref wl_output_transform
*/
static inline bool
wl_output_transform_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_OUTPUT_TRANSFORM_NORMAL:
return version >= 1;
case WL_OUTPUT_TRANSFORM_90:
return version >= 1;
case WL_OUTPUT_TRANSFORM_180:
return version >= 1;
case WL_OUTPUT_TRANSFORM_270:
return version >= 1;
case WL_OUTPUT_TRANSFORM_FLIPPED:
return version >= 1;
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
return version >= 1;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
return version >= 1;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
return version >= 1;
default:
return false;
}
}
#endif /* WL_OUTPUT_TRANSFORM_ENUM_IS_VALID */
#ifndef WL_OUTPUT_MODE_ENUM
#define WL_OUTPUT_MODE_ENUM
/**
@ -4022,6 +4636,26 @@ enum wl_output_mode {
};
#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.
*
* @return true on success, false on error.
* @ref wl_output_mode
*/
static inline bool
wl_output_mode_is_valid(uint32_t value, uint32_t version) {
uint32_t valid = 0;
if (version >= 1)
valid |= WL_OUTPUT_MODE_CURRENT;
if (version >= 1)
valid |= WL_OUTPUT_MODE_PREFERRED;
return (value & ~valid) == 0;
}
#endif /* WL_OUTPUT_MODE_ENUM_IS_VALID */
/**
* @ingroup iface_wl_output
* @struct wl_output_interface
@ -4190,6 +4824,26 @@ enum wl_subcompositor_error {
};
#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.
*
* @return true on success, false on error.
* @ref wl_subcompositor_error
*/
static inline bool
wl_subcompositor_error_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE:
return version >= 1;
default:
return false;
}
}
#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM_IS_VALID */
/**
* @ingroup iface_wl_subcompositor
* @struct wl_subcompositor_interface
@ -4245,6 +4899,26 @@ enum wl_subsurface_error {
};
#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.
*
* @return true on success, false on error.
* @ref wl_subsurface_error
*/
static inline bool
wl_subsurface_error_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case WL_SUBSURFACE_ERROR_BAD_SURFACE:
return version >= 1;
default:
return false;
}
}
#endif /* WL_SUBSURFACE_ERROR_ENUM_IS_VALID */
/**
* @ingroup iface_wl_subsurface
* @struct wl_subsurface_interface

View file

@ -80,13 +80,55 @@ enum intf_A_foo {
* @since 2
*/
INTF_A_FOO_THIRD = 2,
/**
* this is a negative value
* @since 2
*/
INTF_A_FOO_NEGATIVE = -1,
/**
* this is a deprecated value
* @since 2
* @deprecated Deprecated since version 3
*/
INTF_A_FOO_DEPRECATED = 3,
};
/**
* @ingroup iface_intf_A
*/
#define INTF_A_FOO_THIRD_SINCE_VERSION 2
/**
* @ingroup iface_intf_A
*/
#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2
/**
* @ingroup iface_intf_A
*/
#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2
#endif /* INTF_A_FOO_ENUM */
#ifndef INTF_A_BAR_ENUM
#define INTF_A_BAR_ENUM
enum intf_A_bar {
/**
* this is the first
*/
INTF_A_BAR_FIRST = 0x01,
/**
* this is the second
*/
INTF_A_BAR_SECOND = 0x02,
/**
* this is the third
* @since 2
*/
INTF_A_BAR_THIRD = 0x04,
};
/**
* @ingroup iface_intf_A
*/
#define INTF_A_BAR_THIRD_SINCE_VERSION 2
#endif /* INTF_A_BAR_ENUM */
/**
* @ingroup iface_intf_A
* @struct intf_A_listener
@ -96,6 +138,12 @@ struct intf_A_listener {
*/
void (*hey)(void *data,
struct intf_A *intf_A);
/**
* @since 2
* @deprecated Deprecated since version 3
*/
void (*yo)(void *data,
struct intf_A *intf_A);
};
/**
@ -117,6 +165,10 @@ intf_A_add_listener(struct intf_A *intf_A,
* @ingroup iface_intf_A
*/
#define INTF_A_HEY_SINCE_VERSION 1
/**
* @ingroup iface_intf_A
*/
#define INTF_A_YO_SINCE_VERSION 2
/**
* @ingroup iface_intf_A

View file

@ -80,13 +80,55 @@ enum intf_A_foo {
* @since 2
*/
INTF_A_FOO_THIRD = 2,
/**
* this is a negative value
* @since 2
*/
INTF_A_FOO_NEGATIVE = -1,
/**
* this is a deprecated value
* @since 2
* @deprecated Deprecated since version 3
*/
INTF_A_FOO_DEPRECATED = 3,
};
/**
* @ingroup iface_intf_A
*/
#define INTF_A_FOO_THIRD_SINCE_VERSION 2
/**
* @ingroup iface_intf_A
*/
#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2
/**
* @ingroup iface_intf_A
*/
#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2
#endif /* INTF_A_FOO_ENUM */
#ifndef INTF_A_BAR_ENUM
#define INTF_A_BAR_ENUM
enum intf_A_bar {
/**
* this is the first
*/
INTF_A_BAR_FIRST = 0x01,
/**
* this is the second
*/
INTF_A_BAR_SECOND = 0x02,
/**
* this is the third
* @since 2
*/
INTF_A_BAR_THIRD = 0x04,
};
/**
* @ingroup iface_intf_A
*/
#define INTF_A_BAR_THIRD_SINCE_VERSION 2
#endif /* INTF_A_BAR_ENUM */
/**
* @ingroup iface_intf_A
* @struct intf_A_listener
@ -96,6 +138,12 @@ struct intf_A_listener {
*/
void (*hey)(void *data,
struct intf_A *intf_A);
/**
* @since 2
* @deprecated Deprecated since version 3
*/
void (*yo)(void *data,
struct intf_A *intf_A);
};
/**
@ -117,6 +165,10 @@ intf_A_add_listener(struct intf_A *intf_A,
* @ingroup iface_intf_A
*/
#define INTF_A_HEY_SINCE_VERSION 1
/**
* @ingroup iface_intf_A
*/
#define INTF_A_YO_SINCE_VERSION 2
/**
* @ingroup iface_intf_A

View file

@ -25,6 +25,7 @@
* SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
@ -51,11 +52,12 @@ static const struct wl_message intf_A_requests[] = {
static const struct wl_message intf_A_events[] = {
{ "hey", "", small_test_types + 0 },
{ "yo", "2", small_test_types + 0 },
};
WL_EXPORT const struct wl_interface intf_A_interface = {
"intf_A", 3,
3, intf_A_requests,
1, intf_A_events,
2, intf_A_events,
};

View file

@ -25,6 +25,7 @@
* SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
@ -51,11 +52,12 @@ static const struct wl_message intf_A_requests[] = {
static const struct wl_message intf_A_events[] = {
{ "hey", "", small_test_types + 0 },
{ "yo", "2", small_test_types + 0 },
};
WL_EXPORT const struct wl_interface intf_A_interface = {
"intf_A", 3,
3, intf_A_requests,
1, intf_A_events,
2, intf_A_events,
};

View file

@ -25,6 +25,7 @@
* SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
@ -61,11 +62,12 @@ static const struct wl_message intf_A_requests[] = {
static const struct wl_message intf_A_events[] = {
{ "hey", "", small_test_types + 0 },
{ "yo", "2", small_test_types + 0 },
};
WL_PRIVATE const struct wl_interface intf_A_interface = {
"intf_A", 3,
3, intf_A_requests,
1, intf_A_events,
2, intf_A_events,
};

View file

@ -83,13 +83,105 @@ enum intf_A_foo {
* @since 2
*/
INTF_A_FOO_THIRD = 2,
/**
* this is a negative value
* @since 2
*/
INTF_A_FOO_NEGATIVE = -1,
/**
* this is a deprecated value
* @since 2
* @deprecated Deprecated since version 3
*/
INTF_A_FOO_DEPRECATED = 3,
};
/**
* @ingroup iface_intf_A
*/
#define INTF_A_FOO_THIRD_SINCE_VERSION 2
/**
* @ingroup iface_intf_A
*/
#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2
/**
* @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.
*
* @return true on success, false on error.
* @ref intf_A_foo
*/
static inline bool
intf_A_foo_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case INTF_A_FOO_FIRST:
return version >= 1;
case INTF_A_FOO_SECOND:
return version >= 1;
case INTF_A_FOO_THIRD:
return version >= 2;
case (uint32_t)INTF_A_FOO_NEGATIVE:
return version >= 2;
case INTF_A_FOO_DEPRECATED:
return version >= 2;
default:
return false;
}
}
#endif /* INTF_A_FOO_ENUM_IS_VALID */
#ifndef INTF_A_BAR_ENUM
#define INTF_A_BAR_ENUM
enum intf_A_bar {
/**
* this is the first
*/
INTF_A_BAR_FIRST = 0x01,
/**
* this is the second
*/
INTF_A_BAR_SECOND = 0x02,
/**
* this is the third
* @since 2
*/
INTF_A_BAR_THIRD = 0x04,
};
/**
* @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.
*
* @return true on success, false on error.
* @ref intf_A_bar
*/
static inline bool
intf_A_bar_is_valid(uint32_t value, uint32_t version) {
uint32_t valid = 0;
if (version >= 1)
valid |= INTF_A_BAR_FIRST;
if (version >= 1)
valid |= INTF_A_BAR_SECOND;
if (version >= 2)
valid |= INTF_A_BAR_THIRD;
return (value & ~valid) == 0;
}
#endif /* INTF_A_BAR_ENUM_IS_VALID */
/**
* @ingroup iface_intf_A
* @struct intf_A_interface
@ -120,11 +212,16 @@ struct intf_A_interface {
};
#define INTF_A_HEY 0
#define INTF_A_YO 1
/**
* @ingroup iface_intf_A
*/
#define INTF_A_HEY_SINCE_VERSION 1
/**
* @ingroup iface_intf_A
*/
#define INTF_A_YO_SINCE_VERSION 2
/**
* @ingroup iface_intf_A
@ -150,6 +247,17 @@ intf_A_send_hey(struct wl_resource *resource_)
wl_resource_post_event(resource_, INTF_A_HEY);
}
/**
* @ingroup iface_intf_A
* Sends an yo event to the client owning the resource.
* @param resource_ The client's resource
*/
static inline void
intf_A_send_yo(struct wl_resource *resource_)
{
wl_resource_post_event(resource_, INTF_A_YO);
}
#ifdef __cplusplus
}
#endif

View file

@ -83,13 +83,105 @@ enum intf_A_foo {
* @since 2
*/
INTF_A_FOO_THIRD = 2,
/**
* this is a negative value
* @since 2
*/
INTF_A_FOO_NEGATIVE = -1,
/**
* this is a deprecated value
* @since 2
* @deprecated Deprecated since version 3
*/
INTF_A_FOO_DEPRECATED = 3,
};
/**
* @ingroup iface_intf_A
*/
#define INTF_A_FOO_THIRD_SINCE_VERSION 2
/**
* @ingroup iface_intf_A
*/
#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2
/**
* @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.
*
* @return true on success, false on error.
* @ref intf_A_foo
*/
static inline bool
intf_A_foo_is_valid(uint32_t value, uint32_t version) {
switch (value) {
case INTF_A_FOO_FIRST:
return version >= 1;
case INTF_A_FOO_SECOND:
return version >= 1;
case INTF_A_FOO_THIRD:
return version >= 2;
case (uint32_t)INTF_A_FOO_NEGATIVE:
return version >= 2;
case INTF_A_FOO_DEPRECATED:
return version >= 2;
default:
return false;
}
}
#endif /* INTF_A_FOO_ENUM_IS_VALID */
#ifndef INTF_A_BAR_ENUM
#define INTF_A_BAR_ENUM
enum intf_A_bar {
/**
* this is the first
*/
INTF_A_BAR_FIRST = 0x01,
/**
* this is the second
*/
INTF_A_BAR_SECOND = 0x02,
/**
* this is the third
* @since 2
*/
INTF_A_BAR_THIRD = 0x04,
};
/**
* @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.
*
* @return true on success, false on error.
* @ref intf_A_bar
*/
static inline bool
intf_A_bar_is_valid(uint32_t value, uint32_t version) {
uint32_t valid = 0;
if (version >= 1)
valid |= INTF_A_BAR_FIRST;
if (version >= 1)
valid |= INTF_A_BAR_SECOND;
if (version >= 2)
valid |= INTF_A_BAR_THIRD;
return (value & ~valid) == 0;
}
#endif /* INTF_A_BAR_ENUM_IS_VALID */
/**
* @ingroup iface_intf_A
* @struct intf_A_interface
@ -120,11 +212,16 @@ struct intf_A_interface {
};
#define INTF_A_HEY 0
#define INTF_A_YO 1
/**
* @ingroup iface_intf_A
*/
#define INTF_A_HEY_SINCE_VERSION 1
/**
* @ingroup iface_intf_A
*/
#define INTF_A_YO_SINCE_VERSION 2
/**
* @ingroup iface_intf_A
@ -150,6 +247,17 @@ intf_A_send_hey(struct wl_resource *resource_)
wl_resource_post_event(resource_, INTF_A_HEY);
}
/**
* @ingroup iface_intf_A
* Sends an yo event to the client owning the resource.
* @param resource_ The client's resource
*/
static inline void
intf_A_send_yo(struct wl_resource *resource_)
{
wl_resource_post_event(resource_, INTF_A_YO);
}
#ifdef __cplusplus
}
#endif

View file

@ -49,10 +49,21 @@
<event name="hey"/>
<event name="yo" since="2" deprecated-since="3"/>
<enum name="foo">
<entry name="first" value="0" summary="this is the first"/>
<entry name="second" value="1" summary="this is the second"/>
<entry name="third" value="2" since="2" summary="this is the third"/>
<entry name="negative" value="-1" since="2" summary="this is a negative value"/>
<entry name="deprecated" value="3" since="2" deprecated-since="3" summary="this is a deprecated value"/>
</enum>
<enum name="bar" bitfield="true">
<entry name="first" value="0x01" summary="this is the first"/>
<entry name="second" value="0x02" summary="this is the second"/>
<entry name="third" value="0x04" since="2" summary="this is the third"/>
</enum>
</interface>
</protocol>

View file

@ -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, &registry_listener_filtered, data);
wl_registry_add_listener(registry, &registry_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;
@ -1492,6 +1492,10 @@ send_overflow_client(void *data)
char tmp = '\0';
int sock, optval = 16384;
/* By default, client buffers are now unbounded, set a limit to cause
* an overflow, otherwise the client buffers will grow indefinitely. */
wl_display_set_max_buffer_size(c->wl_display, 4096);
/* Limit the send buffer size for the display socket to guarantee
* that the test will cause an overflow. */
sock = wl_display_get_fd(c->wl_display);
@ -1505,6 +1509,7 @@ send_overflow_client(void *data)
* within <=4096 iterations. */
for (i = 0; i < 1000000; i++) {
noop_request(c);
fprintf(stderr, "Send loop %i\n", i);
err = wl_display_get_error(c->wl_display);
if (err)
break;
@ -1514,9 +1519,9 @@ send_overflow_client(void *data)
* check verifies that the initial/final FD counts are the same */
assert(write(pipes[1], &tmp, sizeof(tmp)) == (ssize_t)sizeof(tmp));
/* Expect an error */
/* Expect an error - ring_buffer_ensure_space() returns E2BIG */
fprintf(stderr, "Send loop failed on try %d, err = %d, %s\n", i, err, strerror(err));
assert(err == EAGAIN);
assert(err == EAGAIN || err == E2BIG);
client_disconnect_nocheck(c);
}
@ -1593,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;
@ -1643,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;
@ -1690,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)
{

View file

@ -0,0 +1,28 @@
#include <assert.h>
#include "data/small-server-core.h"
int
main(int argc, char *argv[]) {
assert(intf_A_foo_is_valid(INTF_A_FOO_FIRST, 1));
assert(intf_A_foo_is_valid(INTF_A_FOO_FIRST, 2));
assert(!intf_A_foo_is_valid(INTF_A_FOO_THIRD, 1));
assert(intf_A_foo_is_valid(INTF_A_FOO_THIRD, 2));
assert(intf_A_foo_is_valid(INTF_A_FOO_NEGATIVE, 2));
assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST, 1));
assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST, 2));
assert(intf_A_bar_is_valid(INTF_A_BAR_SECOND, 1));
assert(intf_A_bar_is_valid(INTF_A_BAR_SECOND, 2));
assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_SECOND, 1));
assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_SECOND, 2));
assert(!intf_A_bar_is_valid(INTF_A_BAR_THIRD, 1));
assert(!intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_THIRD, 1));
assert(intf_A_bar_is_valid(INTF_A_BAR_THIRD, 2));
assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_THIRD, 2));
assert(!intf_A_bar_is_valid(0xFF, 1));
assert(!intf_A_bar_is_valid(0xFF, 2));
}

View file

@ -1,107 +0,0 @@
/*
* Copyright © 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include "wayland-private.h"
volatile double global_d;
static void
noop_conversion(void)
{
wl_fixed_t f;
union {
int64_t i;
double d;
} u;
for (f = 0; f < INT32_MAX; f++) {
u.i = f;
global_d = u.d;
}
}
static void
magic_conversion(void)
{
wl_fixed_t f;
for (f = 0; f < INT32_MAX; f++)
global_d = wl_fixed_to_double(f);
}
static void
mul_conversion(void)
{
wl_fixed_t f;
/* This will get optimized into multiplication by 1/256 */
for (f = 0; f < INT32_MAX; f++)
global_d = f / 256.0;
}
double factor = 256.0;
static void
div_conversion(void)
{
wl_fixed_t f;
for (f = 0; f < INT32_MAX; f++)
global_d = f / factor;
}
static void
benchmark(const char *s, void (*f)(void))
{
struct timespec start, stop, elapsed;
clock_gettime(CLOCK_MONOTONIC, &start);
f();
clock_gettime(CLOCK_MONOTONIC, &stop);
elapsed.tv_sec = stop.tv_sec - start.tv_sec;
elapsed.tv_nsec = stop.tv_nsec - start.tv_nsec;
if (elapsed.tv_nsec < 0) {
elapsed.tv_nsec += 1000000000;
elapsed.tv_sec--;
}
printf("benchmarked %s:\t%ld.%09lds\n",
s, elapsed.tv_sec, elapsed.tv_nsec);
}
int main(void)
{
benchmark("noop", noop_conversion);
benchmark("magic", magic_conversion);
benchmark("div", div_conversion);
benchmark("mul", mul_conversion);
return 0;
}

View file

@ -54,16 +54,7 @@ tests_protocol_c = custom_target(
output: 'tests-protocol.c'
)
benchmark(
'fixed-benchmark',
executable(
'fixed-benchmark',
'fixed-benchmark.c',
dependencies: [ test_runner_dep, rt_dep ]
)
)
executable(
exec_fd_leak_checker = executable(
'exec-fd-leak-checker',
'exec-fd-leak-checker.c',
dependencies: test_runner_dep
@ -84,86 +75,137 @@ endif
sed_path = find_program('sed').full_path()
if get_option('scanner')
scanner_test_env = [
'TEST_DATA_DIR=@0@/data'.format(meson.current_source_dir()),
'TEST_OUTPUT_DIR=@0@/output'.format(meson.current_build_dir()),
'SED=@0@'.format(sed_path),
'WAYLAND_SCANNER=@0@'.format(wayland_scanner.full_path()),
]
test(
'scanner-test',
find_program('scanner-test.sh'),
env: [
'TEST_DATA_DIR=@0@/data'.format(meson.current_source_dir()),
'TEST_OUTPUT_DIR=@0@/output'.format(meson.current_build_dir()),
'SED=@0@'.format(sed_path),
'WAYLAND_SCANNER=@0@'.format(wayland_scanner.full_path()),
],
env: scanner_test_env,
)
run_target(
'gen-scanner-test',
command: find_program('scanner-test-gen.sh'),
env: scanner_test_env,
)
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': [],
'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()),

View file

@ -34,7 +34,6 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdarg.h>
#include <fcntl.h>
@ -45,50 +44,20 @@
#include "test-runner.h"
#include "wayland-os.h"
extern int (*wl_socket)(int domain, int type, int protocol);
extern int (*wl_fcntl)(int fildes, int cmd, ...);
extern ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags);
extern int (*wl_epoll_create1)(int flags);
static int fall_back;
/* Play nice with sanitizers
*
* Sanitizers need to intercept syscalls in the compiler run-time library. As
* this isn't a separate ELF object, the usual dlsym(RTLD_NEXT) approach won't
* work: there can only be one function named "socket" etc. To support this, the
* sanitizer library names its interceptors with the prefix __interceptor_ ("__"
* being reserved for the implementation) and then weakly aliases it to the real
* function. The functions we define below will override the weak alias, and we
* can call them by the __interceptor_ name directly. This allows the sanitizer
* to do its work before calling the next version of the function via dlsym.
*
* However! We also don't know which of these functions the sanitizer actually
* wants to override, so we have to declare our own weak symbols for
* __interceptor_ and check at run time if they linked to anything or not.
*/
static int wrapped_calls_socket = 0;
static int wrapped_calls_fcntl = 0;
static int wrapped_calls_recvmsg = 0;
static int wrapped_calls_epoll_create1 = 0;
#define DECL(ret_type, func, ...) \
ret_type __interceptor_ ## func(__VA_ARGS__) __attribute__((weak)); \
static ret_type (*real_ ## func)(__VA_ARGS__); \
static int wrapped_calls_ ## func;
#define REAL(func) (__interceptor_ ## func) ? \
__interceptor_ ## func : \
(__typeof__(&__interceptor_ ## func))dlsym(RTLD_NEXT, #func)
DECL(int, socket, int, int, int);
DECL(int, fcntl, int, int, ...);
DECL(ssize_t, recvmsg, int, struct msghdr *, int);
DECL(int, epoll_create1, int);
static void
init_fallbacks(int do_fallbacks)
{
fall_back = do_fallbacks;
real_socket = REAL(socket);
real_fcntl = REAL(fcntl);
real_recvmsg = REAL(recvmsg);
real_epoll_create1 = REAL(epoll_create1);
}
__attribute__ ((visibility("default"))) int
socket(int domain, int type, int protocol)
static int
socket_wrapper(int domain, int type, int protocol)
{
wrapped_calls_socket++;
@ -97,11 +66,11 @@ socket(int domain, int type, int protocol)
return -1;
}
return real_socket(domain, type, protocol);
return socket(domain, type, protocol);
}
__attribute__ ((visibility("default"))) int
(fcntl)(int fd, int cmd, ...)
static int
fcntl_wrapper(int fd, int cmd, ...)
{
va_list ap;
int arg;
@ -131,13 +100,13 @@ __attribute__ ((visibility("default"))) int
}
if (has_arg) {
return real_fcntl(fd, cmd, arg);
return fcntl(fd, cmd, arg);
}
return real_fcntl(fd, cmd);
return fcntl(fd, cmd);
}
__attribute__ ((visibility("default"))) ssize_t
recvmsg(int sockfd, struct msghdr *msg, int flags)
static ssize_t
recvmsg_wrapper(int sockfd, struct msghdr *msg, int flags)
{
wrapped_calls_recvmsg++;
@ -146,11 +115,11 @@ recvmsg(int sockfd, struct msghdr *msg, int flags)
return -1;
}
return real_recvmsg(sockfd, msg, flags);
return recvmsg(sockfd, msg, flags);
}
__attribute__ ((visibility("default"))) int
epoll_create1(int flags)
static int
epoll_create1_wrapper(int flags)
{
wrapped_calls_epoll_create1++;
@ -160,7 +129,17 @@ epoll_create1(int flags)
return -1;
}
return real_epoll_create1(flags);
return epoll_create1(flags);
}
static void
init_fallbacks(int do_fallbacks)
{
fall_back = do_fallbacks;
wl_fcntl = fcntl_wrapper;
wl_socket = socket_wrapper;
wl_recvmsg = recvmsg_wrapper;
wl_epoll_create1 = epoll_create1_wrapper;
}
static void
@ -256,10 +235,12 @@ setup_marshal_data(struct marshal_data *data)
assert(socketpair(AF_UNIX,
SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
data->read_connection = wl_connection_create(data->s[0]);
data->read_connection = wl_connection_create(data->s[0],
WL_BUFFER_DEFAULT_MAX_SIZE);
assert(data->read_connection);
data->write_connection = wl_connection_create(data->s[1]);
data->write_connection = wl_connection_create(data->s[1],
WL_BUFFER_DEFAULT_MAX_SIZE);
assert(data->write_connection);
}

View file

@ -118,6 +118,8 @@ TEST(proxy_tag)
wl_proxy_set_tag((struct wl_proxy *) client.callback_b,
&tag_b);
assert(wl_proxy_get_display((struct wl_proxy *) client.callback_b) == client.display);
wl_display_flush(client.display);
while (server.sync_count < 2) {

View file

@ -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])
@ -383,7 +384,7 @@ client_test_queue_destroy_with_attached_proxies(void)
/* Check that the log contains some information about the attached
* wl_callback proxy. */
log = map_file(client_log_fd, &log_len);
ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u",
ret = snprintf(callback_name, sizeof(callback_name), "wl_callback#%u",
wl_proxy_get_id((struct wl_proxy *) callback));
assert(ret > 0 && ret < (int)sizeof(callback_name) &&
"callback name creation failed (possibly truncated)");
@ -456,7 +457,7 @@ client_test_queue_destroy_default_with_attached_proxies(void)
/* Check that the log does not contain any warning about the attached
* wl_callback proxy. */
log = maybe_map_file(client_log_fd, &log_len);
ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u",
ret = snprintf(callback_name, sizeof(callback_name), "wl_callback#%u",
wl_proxy_get_id((struct wl_proxy *) callback));
assert(ret > 0 && ret < (int)sizeof(callback_name) &&
"callback name creation failed (possibly truncated)");
@ -471,6 +472,168 @@ client_test_queue_destroy_default_with_attached_proxies(void)
free(callback);
}
static void
check_queue_name(struct wl_proxy *proxy, const char *name)
{
struct wl_event_queue *queue;
const char *queue_name;
queue = wl_proxy_get_queue(proxy);
queue_name = wl_event_queue_get_name(queue);
if (!name)
assert(!queue_name);
else
assert(strcmp(queue_name, name) == 0);
}
static struct wl_callback *
roundtrip_named_queue_nonblock(struct wl_display *display,
struct wl_event_queue *queue,
const char *name)
{
struct wl_callback *callback;
struct wl_display *wrapped_display = NULL;
if (queue) {
wrapped_display = wl_proxy_create_wrapper(display);
assert(wrapped_display);
wl_proxy_set_queue((struct wl_proxy *) wrapped_display, queue);
check_queue_name((struct wl_proxy *) wrapped_display, name);
callback = wl_display_sync(wrapped_display);
} else
callback = wl_display_sync(display);
check_queue_name((struct wl_proxy *) callback, name);
if (wrapped_display)
wl_proxy_wrapper_destroy(wrapped_display);
assert(callback != NULL);
return callback;
}
static void
client_test_queue_names(void)
{
struct wl_event_queue *queue1, *queue2, *queue3;
struct wl_display *display;
struct wl_callback *callback1, *callback2, *callback3, *callback4;
struct wl_event_queue *default_queue;
char *log;
size_t log_len;
const char *default_queue_name;
display = wl_display_connect(NULL);
assert(display);
default_queue = wl_proxy_get_queue((struct wl_proxy *) display);
default_queue_name = wl_event_queue_get_name(default_queue);
assert(strcmp(default_queue_name, "Default Queue") == 0);
/* Create some event queues both with and without names. */
queue1 = wl_display_create_queue_with_name(display, "First");
assert(queue1);
queue2 = wl_display_create_queue_with_name(display, "Second");
assert(queue2);
queue3 = wl_display_create_queue(display);
assert(queue3);
/* Create some requests and ensure their queues have the expected
* names.
*/
callback1 = roundtrip_named_queue_nonblock(display, queue1, "First");
callback2 = roundtrip_named_queue_nonblock(display, queue2, "Second");
callback3 = roundtrip_named_queue_nonblock(display, queue3, NULL);
callback4 = roundtrip_named_queue_nonblock(display, NULL, "Default Queue");
/* Destroy one queue with proxies still attached so we can verify
* that the queue name is in the log message. */
wl_event_queue_destroy(queue2);
log = map_file(client_log_fd, &log_len);
assert(strstr(log, "Second"));
/* There's no reason for the First queue name to be present. */
assert(!strstr(log, "First"));
munmap(log, log_len);
wl_callback_destroy(callback1);
wl_callback_destroy(callback2);
wl_callback_destroy(callback3);
wl_callback_destroy(callback4);
wl_event_queue_destroy(queue1);
wl_event_queue_destroy(queue3);
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)
@ -597,3 +760,39 @@ TEST(queue_destroy_default_with_attached_proxies)
display_destroy(d);
}
TEST(queue_names)
{
struct display *d = display_create();
test_set_timeout(2);
client_create_noarg(d, client_test_queue_names);
display_run(d);
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);
}

View file

@ -206,3 +206,60 @@ TEST(free_without_remove)
assert(a.link.next == a.link.prev && a.link.next == NULL);
assert(b.link.next == b.link.prev && b.link.next == NULL);
}
static enum wl_iterator_result
client_resource_check(struct wl_resource* resource, void* data)
{
/* Ensure there is no iteration over already freed resources. */
assert(!wl_resource_get_user_data(resource));
return WL_ITERATOR_CONTINUE;
}
static void
resource_destroy_notify(struct wl_listener *l, void *data)
{
struct wl_resource* resource = data;
struct wl_client* client = resource->client;
wl_client_for_each_resource(client, client_resource_check, NULL);
/* Set user data to flag the resource has been deleted. The resource should
* not be accessible from this point forward. */
wl_resource_set_user_data(resource, client);
}
TEST(resource_destroy_iteration)
{
struct wl_display *display;
struct wl_client *client;
struct wl_resource *resource1;
struct wl_resource *resource2;
int s[2];
struct wl_listener destroy_listener1 = {
.notify = &resource_destroy_notify
};
struct wl_listener destroy_listener2 = {
.notify = &resource_destroy_notify
};
assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
display = wl_display_create();
assert(display);
client = wl_client_create(display, s[0]);
assert(client);
resource1 = wl_resource_create(client, &wl_callback_interface, 1, 0);
resource2 = wl_resource_create(client, &wl_callback_interface, 1, 0);
assert(resource1);
assert(resource2);
wl_resource_add_destroy_listener(resource1, &destroy_listener1);
wl_resource_add_destroy_listener(resource2, &destroy_listener2);
wl_client_destroy(client);
close(s[0]);
close(s[1]);
wl_display_destroy(display);
}

26
tests/scanner-test-gen.sh Executable file
View file

@ -0,0 +1,26 @@
#!/bin/sh -eu
generate() {
"$WAYLAND_SCANNER" $1 < "$TEST_DATA_DIR/$2" > "$TEST_DATA_DIR/$3"
"$SED" -i -e 's/Generated by wayland-scanner [0-9.]*/SCANNER TEST/' \
"$TEST_DATA_DIR/$3"
}
generate "code" "example.xml" "example-code.c"
generate "client-header" "example.xml" "example-client.h"
generate "server-header" "example.xml" "example-server.h"
generate "enum-header" "example.xml" "example-enum.h"
generate "code" "small.xml" "small-code.c"
generate "client-header" "small.xml" "small-client.h"
generate "server-header" "small.xml" "small-server.h"
generate "-c code" "small.xml" "small-code-core.c"
generate "-c client-header" "small.xml" "small-client-core.h"
generate "-c server-header" "small.xml" "small-server-core.h"
generate "private-code" "small.xml" "small-private-code.c"
generate "code" "empty.xml" "empty-code.c"
generate "client-header" "empty.xml" "empty-client.h"
generate "server-header" "empty.xml" "empty-server.h"

View file

@ -53,6 +53,7 @@ verify_error() {
generate_and_compare "code" "example.xml" "example-code.c"
generate_and_compare "client-header" "example.xml" "example-client.h"
generate_and_compare "server-header" "example.xml" "example-server.h"
generate_and_compare "enum-header" "example.xml" "example-enum.h"
generate_and_compare "code" "small.xml" "small-code.c"
generate_and_compare "client-header" "small.xml" "small-client.h"
@ -67,6 +68,10 @@ generate_and_compare "code" "small.xml" "small-code.c"
generate_and_compare "public-code" "small.xml" "small-code.c"
generate_and_compare "private-code" "small.xml" "small-private-code.c"
generate_and_compare "code" "empty.xml" "empty-code.c"
generate_and_compare "client-header" "empty.xml" "empty-client.h"
generate_and_compare "server-header" "empty.xml" "empty-server.h"
verify_error "bad-identifier-arg.xml" "bad-identifier-arg.log" 7
verify_error "bad-identifier-entry.xml" "bad-identifier-entry.log" 8
verify_error "bad-identifier-enum.xml" "bad-identifier-enum.log" 6

View file

@ -103,26 +103,23 @@ handle_client_destroy(void *data)
{
struct client_info *ci = data;
struct display *d;
siginfo_t status;
int status;
d = ci->display;
assert(waitid(P_PID, ci->pid, &status, WEXITED) != -1);
assert(waitpid(ci->pid, &status, 0) != -1);
switch (status.si_code) {
case CLD_KILLED:
case CLD_DUMPED:
if (WIFSIGNALED(status)) {
fprintf(stderr, "Client '%s' was killed by signal %d\n",
ci->name, status.si_status);
ci->kill_code = status.si_status;
break;
case CLD_EXITED:
if (status.si_status != EXIT_SUCCESS)
fprintf(stderr, "Client '%s' exited with code %d\n",
ci->name, status.si_status);
ci->name, WTERMSIG(status));
ci->kill_code = WTERMSIG(status);
ci->exit_code = status.si_status;
break;
} else if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != EXIT_SUCCESS)
fprintf(stderr, "Client '%s' exited with code %d\n",
ci->name, WEXITSTATUS(status));
ci->exit_code = WEXITSTATUS(status);
}
++d->clients_terminated_no;
@ -510,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);

View file

@ -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))

View file

@ -61,6 +61,33 @@ count_open_fds(void)
assert(error == 0 && "sysctl KERN_PROC_NFDS failed.");
return nfds;
}
#elif defined(__OpenBSD__)
#include <sys/sysctl.h>
/*
* On OpenBSD, get file descriptor information using sysctl()
*/
int
count_open_fds(void)
{
int error;
int mib[6];
size_t size;
mib[0] = CTL_KERN;
mib[1] = KERN_FILE;
mib[2] = KERN_FILE_BYPID;
mib[3] = getpid();
mib[4] = sizeof(struct kinfo_file);
mib[5] = 0;
/* find the size required to store all the entries */
error = sysctl(mib, 6, NULL, &size, NULL, 0);
assert(error != -1 && "sysctl KERN_FILE_BYPID failed.");
/* return the current number of entries */
return size / sizeof(struct kinfo_file);
}
#else
int
count_open_fds(void)

View file

@ -308,6 +308,13 @@ is_debugger_attached(void)
return rc;
}
#else
static int
is_debugger_attached(void)
{
/* 0=debugger can't be determined */
return 0;
}
#endif
int main(int argc, char *argv[])
@ -315,7 +322,7 @@ int main(int argc, char *argv[])
const struct test *t;
pid_t pid;
int total, pass;
siginfo_t info;
int info;
if (isatty(fileno(stderr)))
is_atty = 1;
@ -358,37 +365,32 @@ int main(int argc, char *argv[])
if (pid == 0)
run_test(t); /* never returns */
if (waitid(P_PID, pid, &info, WEXITED)) {
if (waitpid(pid, &info, 0) == -1) {
stderr_set_color(RED);
fprintf(stderr, "waitid failed: %s\n",
fprintf(stderr, "waitpid failed: %s\n",
strerror(errno));
stderr_reset_color();
abort();
}
switch (info.si_code) {
case CLD_EXITED:
if (info.si_status == EXIT_SUCCESS)
if (WIFEXITED(info)) {
if (WEXITSTATUS(info) == EXIT_SUCCESS)
success = !t->must_fail;
else
success = t->must_fail;
stderr_set_color(success ? GREEN : RED);
fprintf(stderr, "test \"%s\":\texit status %d",
t->name, info.si_status);
t->name, WEXITSTATUS(info));
break;
case CLD_KILLED:
case CLD_DUMPED:
} else if (WIFSIGNALED(info)) {
if (t->must_fail)
success = 1;
stderr_set_color(success ? GREEN : RED);
fprintf(stderr, "test \"%s\":\tsignal %d",
t->name, info.si_status);
break;
t->name, WTERMSIG(info));
}
if (success) {