2008-12-02 15:15:01 -05:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2008 Kristian Høgsberg
|
|
|
|
|
*
|
2015-06-10 10:54:15 -07:00
|
|
|
* 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:
|
2008-12-02 15:15:01 -05:00
|
|
|
*
|
2015-06-10 10:54:15 -07:00
|
|
|
* 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.
|
2008-12-02 15:15:01 -05:00
|
|
|
*/
|
|
|
|
|
|
2011-04-11 09:24:11 -04:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
|
2019-07-20 23:36:29 +03:00
|
|
|
#include <stdbool.h>
|
2008-09-30 09:46:10 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
#include <stdio.h>
|
2008-11-28 19:12:45 -05:00
|
|
|
#include <stdarg.h>
|
2008-09-30 09:46:10 -04:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/un.h>
|
2008-11-06 10:38:17 -05:00
|
|
|
#include <dlfcn.h>
|
2010-12-06 16:56:28 -05:00
|
|
|
#include <sys/time.h>
|
2011-04-11 09:24:11 -04:00
|
|
|
#include <fcntl.h>
|
2021-08-31 18:59:33 +09:00
|
|
|
#include <sys/eventfd.h>
|
2011-04-13 09:38:29 +02:00
|
|
|
#include <sys/file.h>
|
|
|
|
|
#include <sys/stat.h>
|
2008-10-08 12:48:46 -04:00
|
|
|
|
2016-05-17 21:02:01 -06:00
|
|
|
#include "wayland-util.h"
|
2011-11-18 13:46:56 -05:00
|
|
|
#include "wayland-private.h"
|
2019-11-05 09:09:50 -06:00
|
|
|
#include "wayland-server-private.h"
|
2010-08-10 14:12:05 -04:00
|
|
|
#include "wayland-server.h"
|
2012-03-21 11:11:26 +02:00
|
|
|
#include "wayland-os.h"
|
2008-09-30 09:46:10 -04:00
|
|
|
|
2012-06-15 21:09:00 +00:00
|
|
|
/* This is the size of the char array in struct sock_addr_un.
|
2015-06-10 11:26:29 -07:00
|
|
|
* No Wayland socket can be created with a path longer than this,
|
|
|
|
|
* including the null terminator.
|
|
|
|
|
*/
|
2012-06-15 21:09:00 +00:00
|
|
|
#ifndef UNIX_PATH_MAX
|
|
|
|
|
#define UNIX_PATH_MAX 108
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define LOCK_SUFFIX ".lock"
|
|
|
|
|
#define LOCK_SUFFIXLEN 5
|
|
|
|
|
|
2010-12-01 15:36:20 -05:00
|
|
|
struct wl_socket {
|
|
|
|
|
int fd;
|
2011-04-13 09:38:29 +02:00
|
|
|
int fd_lock;
|
2010-12-01 15:36:20 -05:00
|
|
|
struct sockaddr_un addr;
|
2012-06-15 21:09:00 +00:00
|
|
|
char lock_addr[UNIX_PATH_MAX + LOCK_SUFFIXLEN];
|
2010-12-01 15:36:20 -05:00
|
|
|
struct wl_list link;
|
2011-12-22 16:52:37 +02:00
|
|
|
struct wl_event_source *source;
|
2014-05-08 11:25:34 -04:00
|
|
|
char *display_name;
|
2010-12-01 15:36:20 -05:00
|
|
|
};
|
|
|
|
|
|
2008-09-30 09:46:10 -04:00
|
|
|
struct wl_client {
|
2008-10-08 12:48:46 -04:00
|
|
|
struct wl_connection *connection;
|
2008-09-30 09:46:10 -04:00
|
|
|
struct wl_event_source *source;
|
|
|
|
|
struct wl_display *display;
|
2011-08-19 16:57:48 -04:00
|
|
|
struct wl_resource *display_resource;
|
2011-06-14 10:35:46 +02:00
|
|
|
struct wl_list link;
|
2011-08-19 22:50:53 -04:00
|
|
|
struct wl_map objects;
|
2017-01-24 16:34:29 +02:00
|
|
|
struct wl_priv_signal destroy_signal;
|
2022-07-21 11:07:04 +01:00
|
|
|
struct wl_priv_signal destroy_late_signal;
|
2021-03-15 22:21:12 +00:00
|
|
|
pid_t pid;
|
|
|
|
|
uid_t uid;
|
|
|
|
|
gid_t gid;
|
2023-05-22 20:10:40 +02:00
|
|
|
bool error;
|
2017-01-24 16:34:29 +02:00
|
|
|
struct wl_priv_signal resource_created_signal;
|
2021-10-25 04:34:49 +02:00
|
|
|
void *data;
|
|
|
|
|
wl_user_data_destroy_func_t data_dtor;
|
2008-09-30 09:46:10 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct wl_display {
|
|
|
|
|
struct wl_event_loop *loop;
|
2023-05-22 20:10:40 +02:00
|
|
|
bool run;
|
2008-10-07 10:10:36 -04:00
|
|
|
|
2023-01-24 23:55:29 +01:00
|
|
|
uint32_t next_global_name;
|
Switch protocol to using serial numbers for ordering events and requests
The wayland protocol, as X, uses timestamps to match up certain
requests with input events. The problem is that sometimes we need to
send out an event that doesn't have a corresponding timestamped input
event. For example, the pointer focus surface goes away and new
surface needs to receive a pointer enter event. These events are
normally timestamped with the evdev event timestamp, but in this case,
we don't have a evdev timestamp. So we have to go to gettimeofday (or
clock_gettime()) and then we don't know if it's coming from the same
time source etc.
However for all these cases we don't need a real time timestamp, we
just need a serial number that encodes the order of events inside the
server. So we introduce a serial number mechanism that we can use to
order events. We still need real-time timestamps for actual input
device events (motion, buttons, keys, touch), to be able to reason
about double-click speed and movement speed so events that correspond to user input carry both a serial number and a timestamp.
The serial number also give us a mechanism to key together events that
are "logically the same" such as a unicode event and a keycode event,
or a motion event and a relative event from a raw device.
2012-04-11 22:25:51 -04:00
|
|
|
uint32_t serial;
|
2008-11-02 10:12:29 -05:00
|
|
|
|
2012-10-08 13:53:47 -04:00
|
|
|
struct wl_list registry_resource_list;
|
2008-11-23 19:10:23 -05:00
|
|
|
struct wl_list global_list;
|
2010-12-01 15:36:20 -05:00
|
|
|
struct wl_list socket_list;
|
2011-06-14 10:35:46 +02:00
|
|
|
struct wl_list client_list;
|
2016-08-12 09:33:06 +02:00
|
|
|
struct wl_list protocol_loggers;
|
2013-01-11 14:29:32 -06:00
|
|
|
|
2017-01-24 16:34:28 +02:00
|
|
|
struct wl_priv_signal destroy_signal;
|
|
|
|
|
struct wl_priv_signal create_client_signal;
|
2013-08-06 20:05:53 +02:00
|
|
|
|
|
|
|
|
struct wl_array additional_shm_formats;
|
2016-10-18 16:23:39 +02:00
|
|
|
|
|
|
|
|
wl_display_global_filter_func_t global_filter;
|
|
|
|
|
void *global_filter_data;
|
2021-08-31 18:59:33 +09:00
|
|
|
|
|
|
|
|
int terminate_efd;
|
|
|
|
|
struct wl_event_source *term_source;
|
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
2021-09-25 22:34:44 -04:00
|
|
|
|
|
|
|
|
size_t max_buffer_size;
|
2008-09-30 09:46:10 -04:00
|
|
|
};
|
|
|
|
|
|
2008-12-21 23:37:12 -05:00
|
|
|
struct wl_global {
|
2013-07-08 18:45:41 -04:00
|
|
|
struct wl_display *display;
|
2011-08-19 16:57:48 -04:00
|
|
|
const struct wl_interface *interface;
|
|
|
|
|
uint32_t name;
|
2013-07-08 18:45:41 -04:00
|
|
|
uint32_t version;
|
2011-08-19 16:57:48 -04:00
|
|
|
void *data;
|
2011-08-19 11:05:01 -04:00
|
|
|
wl_global_bind_func_t bind;
|
2008-12-21 23:37:12 -05:00
|
|
|
struct wl_list link;
|
2019-07-20 23:36:29 +03:00
|
|
|
bool removed;
|
2008-12-21 23:37:12 -05:00
|
|
|
};
|
|
|
|
|
|
2013-06-27 20:09:18 -05:00
|
|
|
struct wl_resource {
|
|
|
|
|
struct wl_object object;
|
|
|
|
|
wl_resource_destroy_func_t destroy;
|
|
|
|
|
struct wl_list link;
|
2017-01-24 16:34:30 +02:00
|
|
|
/* Unfortunately some users of libwayland (e.g. mesa) still use the
|
|
|
|
|
* deprecated wl_resource struct, even if creating it with the new
|
|
|
|
|
* wl_resource_create(). So we cannot change the layout of the struct
|
|
|
|
|
* unless after the data field. */
|
|
|
|
|
struct wl_signal deprecated_destroy_signal;
|
2013-06-27 20:09:18 -05:00
|
|
|
struct wl_client *client;
|
|
|
|
|
void *data;
|
2013-06-27 20:09:20 -05:00
|
|
|
int version;
|
2013-07-17 21:58:46 -05:00
|
|
|
wl_dispatcher_func_t dispatcher;
|
2017-01-24 16:34:30 +02:00
|
|
|
struct wl_priv_signal destroy_signal;
|
2013-06-27 20:09:18 -05:00
|
|
|
};
|
|
|
|
|
|
2016-08-12 09:33:06 +02:00
|
|
|
struct wl_protocol_logger {
|
|
|
|
|
struct wl_list link;
|
|
|
|
|
wl_protocol_logger_func_t func;
|
|
|
|
|
void *user_data;
|
|
|
|
|
};
|
|
|
|
|
|
2013-12-18 20:56:18 -06:00
|
|
|
static int debug_server = 0;
|
2025-05-27 22:40:14 +01:00
|
|
|
static int debug_color = 0;
|
2010-09-07 10:58:19 -04:00
|
|
|
|
2016-08-12 09:33:06 +02:00
|
|
|
static void
|
|
|
|
|
log_closure(struct wl_resource *resource,
|
|
|
|
|
struct wl_closure *closure, int send)
|
|
|
|
|
{
|
|
|
|
|
struct wl_object *object = &resource->object;
|
|
|
|
|
struct wl_display *display = resource->client->display;
|
|
|
|
|
struct wl_protocol_logger *protocol_logger;
|
|
|
|
|
struct wl_protocol_logger_message message;
|
|
|
|
|
|
|
|
|
|
if (debug_server)
|
2025-05-27 22:40:14 +01:00
|
|
|
wl_closure_print(closure, object, send, false, NULL, NULL, debug_color);
|
2016-08-12 09:33:06 +02:00
|
|
|
|
|
|
|
|
if (!wl_list_empty(&display->protocol_loggers)) {
|
|
|
|
|
message.resource = resource;
|
|
|
|
|
message.message_opcode = closure->opcode;
|
|
|
|
|
message.message = closure->message;
|
|
|
|
|
message.arguments_count = closure->count;
|
|
|
|
|
message.arguments = closure->args;
|
|
|
|
|
wl_list_for_each(protocol_logger,
|
|
|
|
|
&display->protocol_loggers, link) {
|
|
|
|
|
protocol_logger->func(protocol_logger->user_data,
|
|
|
|
|
send ? WL_PROTOCOL_LOGGER_EVENT :
|
|
|
|
|
WL_PROTOCOL_LOGGER_REQUEST,
|
|
|
|
|
&message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-24 12:07:21 -06:00
|
|
|
static bool
|
|
|
|
|
verify_objects(struct wl_resource *resource, uint32_t opcode,
|
|
|
|
|
union wl_argument *args)
|
|
|
|
|
{
|
|
|
|
|
struct wl_object *object = &resource->object;
|
|
|
|
|
const char *signature = object->interface->events[opcode].signature;
|
|
|
|
|
struct argument_details arg;
|
|
|
|
|
struct wl_resource *res;
|
|
|
|
|
int count, i;
|
|
|
|
|
|
|
|
|
|
count = arg_count_for_signature(signature);
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
signature = get_next_argument(signature, &arg);
|
|
|
|
|
switch (arg.type) {
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_NEW_ID:
|
|
|
|
|
case WL_ARG_OBJECT:
|
2017-01-24 12:07:21 -06:00
|
|
|
res = (struct wl_resource *) (args[i].o);
|
|
|
|
|
if (res && res->client != resource->client) {
|
|
|
|
|
wl_log("compositor bug: The compositor "
|
|
|
|
|
"tried to use an object from one "
|
|
|
|
|
"client in a '%s.%s' for a different "
|
|
|
|
|
"client.\n", object->interface->name,
|
|
|
|
|
object->interface->events[opcode].name);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-02-15 10:37:34 +01:00
|
|
|
default:
|
|
|
|
|
break;
|
2017-01-24 12:07:21 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-24 12:07:19 -06:00
|
|
|
static void
|
|
|
|
|
handle_array(struct wl_resource *resource, uint32_t opcode,
|
|
|
|
|
union wl_argument *args,
|
|
|
|
|
int (*send_func)(struct wl_closure *, struct wl_connection *))
|
2008-12-21 23:37:12 -05:00
|
|
|
{
|
2012-06-12 17:45:25 -04:00
|
|
|
struct wl_closure *closure;
|
2011-08-18 17:53:50 -04:00
|
|
|
struct wl_object *object = &resource->object;
|
2008-12-21 23:37:12 -05:00
|
|
|
|
2017-01-24 12:07:20 -06:00
|
|
|
if (resource->client->error)
|
|
|
|
|
return;
|
|
|
|
|
|
2017-01-24 12:07:21 -06:00
|
|
|
if (!verify_objects(resource, opcode, args)) {
|
2023-05-22 20:10:40 +02:00
|
|
|
resource->client->error = true;
|
2017-01-24 12:07:21 -06:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-17 21:58:46 -05:00
|
|
|
closure = wl_closure_marshal(object, opcode, args,
|
|
|
|
|
&object->interface->events[opcode]);
|
2010-09-07 21:34:45 -04:00
|
|
|
|
2013-08-06 09:50:14 -07:00
|
|
|
if (closure == NULL) {
|
2023-05-22 20:10:40 +02:00
|
|
|
resource->client->error = true;
|
2011-12-16 10:29:36 +02:00
|
|
|
return;
|
2013-08-06 09:50:14 -07:00
|
|
|
}
|
2011-12-16 10:29:36 +02:00
|
|
|
|
2017-12-06 11:22:17 -06:00
|
|
|
log_closure(resource, closure, true);
|
|
|
|
|
|
2017-01-24 12:07:19 -06:00
|
|
|
if (send_func(closure, resource->client->connection))
|
2023-05-22 20:10:40 +02:00
|
|
|
resource->client->error = true;
|
2010-09-07 21:40:31 -04:00
|
|
|
|
2012-06-12 17:45:25 -04:00
|
|
|
wl_closure_destroy(closure);
|
2008-12-21 23:37:12 -05:00
|
|
|
}
|
|
|
|
|
|
2017-01-24 12:07:19 -06:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode,
|
|
|
|
|
union wl_argument *args)
|
|
|
|
|
{
|
|
|
|
|
handle_array(resource, opcode, args, wl_closure_send);
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-17 16:46:36 -05:00
|
|
|
WL_EXPORT void
|
2013-07-17 21:58:46 -05:00
|
|
|
wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
|
2011-11-17 16:46:36 -05:00
|
|
|
{
|
2013-07-17 21:58:46 -05:00
|
|
|
union wl_argument args[WL_CLOSURE_MAX_ARGS];
|
2011-11-17 16:46:36 -05:00
|
|
|
struct wl_object *object = &resource->object;
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
va_start(ap, opcode);
|
2013-07-17 21:58:46 -05:00
|
|
|
wl_argument_from_va_list(object->interface->events[opcode].signature,
|
|
|
|
|
args, WL_CLOSURE_MAX_ARGS, ap);
|
2011-11-17 16:46:36 -05:00
|
|
|
va_end(ap);
|
|
|
|
|
|
2013-07-17 21:58:46 -05:00
|
|
|
wl_resource_post_event_array(resource, opcode, args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode,
|
|
|
|
|
union wl_argument *args)
|
|
|
|
|
{
|
2017-01-24 12:07:19 -06:00
|
|
|
handle_array(resource, opcode, args, wl_closure_queue);
|
2011-11-17 16:46:36 -05:00
|
|
|
}
|
|
|
|
|
|
2013-07-17 21:58:46 -05:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
|
|
|
|
|
{
|
|
|
|
|
union wl_argument args[WL_CLOSURE_MAX_ARGS];
|
|
|
|
|
struct wl_object *object = &resource->object;
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
va_start(ap, opcode);
|
|
|
|
|
wl_argument_from_va_list(object->interface->events[opcode].signature,
|
|
|
|
|
args, WL_CLOSURE_MAX_ARGS, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
|
|
wl_resource_queue_event_array(resource, opcode, args);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-23 19:25:40 +03:00
|
|
|
/** 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
|
2018-11-20 18:02:49 +11:00
|
|
|
wl_resource_post_error_vargs(struct wl_resource *resource,
|
|
|
|
|
uint32_t code, const char *msg, va_list argp)
|
2011-05-11 10:57:06 -04:00
|
|
|
{
|
2011-09-01 09:53:33 -04:00
|
|
|
struct wl_client *client = resource->client;
|
2011-05-11 10:57:06 -04:00
|
|
|
char buffer[128];
|
|
|
|
|
|
2018-11-20 18:02:49 +11:00
|
|
|
vsnprintf(buffer, sizeof buffer, msg, argp);
|
2011-05-11 10:57:06 -04:00
|
|
|
|
2011-11-28 09:47:15 +02:00
|
|
|
/*
|
|
|
|
|
* When a client aborts, its resources are destroyed in id order,
|
|
|
|
|
* which means the display resource is destroyed first. If destruction
|
|
|
|
|
* of any later resources results in a protocol error, we end up here
|
|
|
|
|
* with a NULL display_resource. Do not try to send errors to an
|
|
|
|
|
* already dead client.
|
|
|
|
|
*/
|
2017-01-24 12:07:20 -06:00
|
|
|
if (client->error || !client->display_resource)
|
2011-11-28 09:47:15 +02:00
|
|
|
return;
|
|
|
|
|
|
2011-08-19 16:57:48 -04:00
|
|
|
wl_resource_post_event(client->display_resource,
|
2011-09-01 09:53:33 -04:00
|
|
|
WL_DISPLAY_ERROR, resource, code, buffer);
|
2023-05-22 20:10:40 +02:00
|
|
|
client->error = true;
|
2018-11-20 18:02:49 +11:00
|
|
|
}
|
|
|
|
|
|
2024-05-23 19:25:05 +03:00
|
|
|
/** 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
|
|
|
|
|
*/
|
2018-11-20 18:02:49 +11:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_resource_post_error(struct wl_resource *resource,
|
|
|
|
|
uint32_t code, const char *msg, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
va_start(ap, msg);
|
|
|
|
|
wl_resource_post_error_vargs(resource, code, msg, ap);
|
|
|
|
|
va_end(ap);
|
2011-05-11 10:57:06 -04:00
|
|
|
}
|
|
|
|
|
|
2017-12-05 09:49:52 +01:00
|
|
|
static void
|
|
|
|
|
destroy_client_with_error(struct wl_client *client, const char *reason)
|
|
|
|
|
{
|
2021-03-15 22:21:12 +00:00
|
|
|
wl_log("%s (pid %u)\n", reason, client->pid);
|
2017-12-05 09:49:52 +01:00
|
|
|
wl_client_destroy(client);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-22 12:06:34 -04:00
|
|
|
static int
|
2008-10-08 12:48:46 -04:00
|
|
|
wl_client_connection_data(int fd, uint32_t mask, void *data)
|
2008-10-07 10:10:36 -04:00
|
|
|
{
|
2008-10-08 12:48:46 -04:00
|
|
|
struct wl_client *client = data;
|
|
|
|
|
struct wl_connection *connection = client->connection;
|
2011-08-18 17:53:50 -04:00
|
|
|
struct wl_resource *resource;
|
2008-10-07 10:10:36 -04:00
|
|
|
struct wl_object *object;
|
2012-06-12 17:45:25 -04:00
|
|
|
struct wl_closure *closure;
|
2010-08-30 09:47:36 -04:00
|
|
|
const struct wl_message *message;
|
2012-03-22 17:21:58 +02:00
|
|
|
uint32_t p[2];
|
2013-07-02 14:57:10 -04:00
|
|
|
uint32_t resource_flags;
|
2015-03-19 03:42:27 -04:00
|
|
|
int opcode, size, since;
|
2012-06-12 17:45:25 -04:00
|
|
|
int len;
|
2008-10-08 12:48:46 -04:00
|
|
|
|
2017-12-05 09:49:52 +01:00
|
|
|
if (mask & WL_EVENT_HANGUP) {
|
2008-10-08 12:48:46 -04:00
|
|
|
wl_client_destroy(client);
|
2011-04-22 12:06:34 -04:00
|
|
|
return 1;
|
2008-10-08 12:48:46 -04:00
|
|
|
}
|
2008-10-08 10:47:59 -04:00
|
|
|
|
2017-12-05 09:49:52 +01:00
|
|
|
if (mask & WL_EVENT_ERROR) {
|
|
|
|
|
destroy_client_with_error(client, "socket error");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
if (mask & WL_EVENT_WRITABLE) {
|
|
|
|
|
len = wl_connection_flush(connection);
|
|
|
|
|
if (len < 0 && errno != EAGAIN) {
|
2017-12-05 09:49:52 +01:00
|
|
|
destroy_client_with_error(
|
|
|
|
|
client, "failed to flush client connection");
|
2012-10-04 16:54:22 -04:00
|
|
|
return 1;
|
|
|
|
|
} else if (len >= 0) {
|
|
|
|
|
wl_event_source_fd_update(client->source,
|
|
|
|
|
WL_EVENT_READABLE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
|
if (mask & WL_EVENT_READABLE) {
|
|
|
|
|
len = wl_connection_read(connection);
|
2014-11-01 17:06:29 +00:00
|
|
|
if (len == 0 || (len < 0 && errno != EAGAIN)) {
|
2017-12-05 09:49:52 +01:00
|
|
|
destroy_client_with_error(
|
|
|
|
|
client, "failed to read client connection");
|
2012-10-04 16:54:22 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-19 09:01:56 -05:00
|
|
|
while (len >= 0 && (size_t) len >= sizeof p) {
|
2008-10-08 12:48:46 -04:00
|
|
|
wl_connection_copy(connection, p, sizeof p);
|
2008-10-07 10:10:36 -04:00
|
|
|
opcode = p[1] & 0xffff;
|
|
|
|
|
size = p[1] >> 16;
|
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 d074d5290263 ("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: d074d5290263 ("connection: Dynamically resize connection buffers").
Fixes: #494
Signed-off-by: Demi Marie Obenour <demi@invisiblethingslab.com>
2024-08-14 21:14:49 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
if (len < size)
|
2008-10-07 10:10:36 -04:00
|
|
|
break;
|
|
|
|
|
|
2011-08-19 22:50:53 -04:00
|
|
|
resource = wl_map_lookup(&client->objects, p[0]);
|
2013-07-02 14:57:10 -04:00
|
|
|
resource_flags = wl_map_lookup_flags(&client->objects, p[0]);
|
2011-08-18 17:53:50 -04:00
|
|
|
if (resource == NULL) {
|
2011-10-11 13:58:18 -04:00
|
|
|
wl_resource_post_error(client->display_resource,
|
2011-09-01 09:53:33 -04:00
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
2012-07-23 19:54:42 +01:00
|
|
|
"invalid object %u", p[0]);
|
2011-08-29 15:01:41 -04:00
|
|
|
break;
|
2008-10-07 10:10:36 -04:00
|
|
|
}
|
2010-08-09 14:34:11 -04:00
|
|
|
|
2011-08-18 17:53:50 -04:00
|
|
|
object = &resource->object;
|
2008-10-07 10:10:36 -04:00
|
|
|
if (opcode >= object->interface->method_count) {
|
2011-10-11 14:36:49 -04:00
|
|
|
wl_resource_post_error(client->display_resource,
|
2011-09-01 09:53:33 -04:00
|
|
|
WL_DISPLAY_ERROR_INVALID_METHOD,
|
2023-05-24 11:24:23 -07:00
|
|
|
"invalid method %d, object %s#%u",
|
2012-03-27 16:36:25 -04:00
|
|
|
opcode,
|
2011-09-01 09:53:33 -04:00
|
|
|
object->interface->name,
|
2012-03-27 16:36:25 -04:00
|
|
|
object->id);
|
2011-08-29 15:01:41 -04:00
|
|
|
break;
|
2008-10-07 10:10:36 -04:00
|
|
|
}
|
2010-08-09 14:34:11 -04:00
|
|
|
|
2010-08-30 09:47:36 -04:00
|
|
|
message = &object->interface->methods[opcode];
|
2015-03-19 03:42:27 -04:00
|
|
|
since = wl_message_get_since(message);
|
2013-07-02 14:57:10 -04:00
|
|
|
if (!(resource_flags & WL_MAP_ENTRY_LEGACY) &&
|
2015-03-19 03:42:27 -04:00
|
|
|
resource->version > 0 && resource->version < since) {
|
2013-07-02 14:57:10 -04:00
|
|
|
wl_resource_post_error(client->display_resource,
|
|
|
|
|
WL_DISPLAY_ERROR_INVALID_METHOD,
|
2015-03-19 03:42:27 -04:00
|
|
|
"invalid method %d (since %d < %d)"
|
2023-05-24 11:24:23 -07:00
|
|
|
", object %s#%u",
|
2015-03-19 03:42:27 -04:00
|
|
|
opcode, resource->version, since,
|
2013-07-02 14:57:10 -04:00
|
|
|
object->interface->name,
|
|
|
|
|
object->id);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-06-12 17:45:25 -04:00
|
|
|
closure = wl_connection_demarshal(client->connection, size,
|
|
|
|
|
&client->objects, message);
|
2010-08-09 14:34:11 -04:00
|
|
|
|
2013-03-28 18:48:09 +00:00
|
|
|
if (closure == NULL && errno == ENOMEM) {
|
|
|
|
|
wl_resource_post_no_memory(resource);
|
|
|
|
|
break;
|
2014-05-05 16:28:26 -07:00
|
|
|
} else if (closure == NULL ||
|
2013-03-28 18:48:09 +00:00
|
|
|
wl_closure_lookup_objects(closure, &client->objects) < 0) {
|
2011-10-11 14:36:49 -04:00
|
|
|
wl_resource_post_error(client->display_resource,
|
2011-09-01 09:53:33 -04:00
|
|
|
WL_DISPLAY_ERROR_INVALID_METHOD,
|
2023-05-24 11:24:23 -07:00
|
|
|
"invalid arguments for %s#%u.%s",
|
2011-09-01 09:53:33 -04:00
|
|
|
object->interface->name,
|
|
|
|
|
object->id,
|
|
|
|
|
message->name);
|
2014-05-05 16:28:26 -07:00
|
|
|
wl_closure_destroy(closure);
|
2011-08-29 15:01:41 -04:00
|
|
|
break;
|
2010-08-30 09:47:36 -04:00
|
|
|
}
|
|
|
|
|
|
2016-08-12 09:33:06 +02:00
|
|
|
log_closure(resource, closure, false);
|
2012-10-09 12:14:34 -04:00
|
|
|
|
2013-07-17 21:58:46 -05:00
|
|
|
if ((resource_flags & WL_MAP_ENTRY_LEGACY) ||
|
|
|
|
|
resource->dispatcher == NULL) {
|
|
|
|
|
wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER,
|
|
|
|
|
object, opcode, client);
|
|
|
|
|
} else {
|
|
|
|
|
wl_closure_dispatch(closure, resource->dispatcher,
|
|
|
|
|
object, opcode);
|
|
|
|
|
}
|
2010-08-30 09:47:36 -04:00
|
|
|
|
2012-06-12 17:45:25 -04:00
|
|
|
wl_closure_destroy(closure);
|
2011-08-29 15:01:41 -04:00
|
|
|
|
|
|
|
|
if (client->error)
|
|
|
|
|
break;
|
2016-01-12 13:12:34 +09:00
|
|
|
|
|
|
|
|
len = wl_connection_pending_input(connection);
|
2008-10-07 10:10:36 -04:00
|
|
|
}
|
2011-04-22 12:06:34 -04:00
|
|
|
|
2017-12-05 09:49:52 +01:00
|
|
|
if (client->error) {
|
|
|
|
|
destroy_client_with_error(client,
|
|
|
|
|
"error in client communication");
|
|
|
|
|
}
|
2011-08-29 15:01:41 -04:00
|
|
|
|
2011-04-22 12:06:34 -04:00
|
|
|
return 1;
|
2008-10-07 10:10:36 -04:00
|
|
|
}
|
|
|
|
|
|
2013-11-13 21:11:17 -08:00
|
|
|
/** Flush pending events to the client
|
|
|
|
|
*
|
|
|
|
|
* \param client The client object
|
|
|
|
|
*
|
|
|
|
|
* Events sent to clients are queued in a buffer and written to the
|
|
|
|
|
* socket later - typically when the compositor has handled all
|
|
|
|
|
* requests and goes back to block in the event loop. This function
|
|
|
|
|
* flushes all queued up events for a client immediately.
|
2015-01-26 11:30:57 -08:00
|
|
|
*
|
2013-11-13 21:11:17 -08:00
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
2011-06-29 11:43:11 -04:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_client_flush(struct wl_client *client)
|
|
|
|
|
{
|
2012-10-04 16:54:22 -04:00
|
|
|
wl_connection_flush(client->connection);
|
2011-06-29 11:43:11 -04:00
|
|
|
}
|
|
|
|
|
|
2013-11-13 21:11:17 -08:00
|
|
|
/** Get the display object for the given client
|
|
|
|
|
*
|
|
|
|
|
* \param client The client object
|
|
|
|
|
* \return The display object the client is associated with.
|
2015-01-26 11:30:57 -08:00
|
|
|
*
|
2013-11-13 21:11:17 -08:00
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
2010-08-17 21:23:10 -04:00
|
|
|
WL_EXPORT struct wl_display *
|
|
|
|
|
wl_client_get_display(struct wl_client *client)
|
|
|
|
|
{
|
|
|
|
|
return client->display;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-07 09:55:49 -04:00
|
|
|
static int
|
|
|
|
|
bind_display(struct wl_client *client, struct wl_display *display);
|
2011-08-19 16:57:48 -04:00
|
|
|
|
2013-11-13 21:11:17 -08:00
|
|
|
/** Create a client for the given file descriptor
|
|
|
|
|
*
|
|
|
|
|
* \param display The display object
|
|
|
|
|
* \param fd The file descriptor for the socket to the client
|
|
|
|
|
* \return The new client object or NULL on failure.
|
|
|
|
|
*
|
|
|
|
|
* Given a file descriptor corresponding to one end of a socket, this
|
|
|
|
|
* function will create a wl_client struct and add the new client to
|
|
|
|
|
* the compositors client list. At that point, the client is
|
|
|
|
|
* initialized and ready to run, as if the client had connected to the
|
|
|
|
|
* servers listening socket. When the client eventually sends
|
|
|
|
|
* requests to the compositor, the wl_client argument to the request
|
|
|
|
|
* handler will be the wl_client returned from this function.
|
|
|
|
|
*
|
|
|
|
|
* The other end of the socket can be passed to
|
|
|
|
|
* wl_display_connect_to_fd() on the client side or used with the
|
|
|
|
|
* WAYLAND_SOCKET environment variable on the client side.
|
|
|
|
|
*
|
2016-08-09 12:46:51 +02:00
|
|
|
* Listeners added with wl_display_add_client_created_listener() will
|
|
|
|
|
* be notified by this function after the client is fully constructed.
|
|
|
|
|
*
|
2013-11-13 21:11:17 -08:00
|
|
|
* On failure this function sets errno accordingly and returns NULL.
|
2015-01-26 11:30:57 -08:00
|
|
|
*
|
2024-05-16 12:39:17 +03:00
|
|
|
* 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().
|
|
|
|
|
*
|
2013-11-13 21:11:17 -08:00
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
2011-04-11 09:15:09 -04:00
|
|
|
WL_EXPORT struct wl_client *
|
2008-10-08 12:48:46 -04:00
|
|
|
wl_client_create(struct wl_display *display, int fd)
|
|
|
|
|
{
|
|
|
|
|
struct wl_client *client;
|
|
|
|
|
|
2015-08-26 12:00:06 +08:00
|
|
|
client = zalloc(sizeof *client);
|
2008-10-08 12:48:46 -04:00
|
|
|
if (client == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2017-01-24 16:34:29 +02:00
|
|
|
wl_priv_signal_init(&client->resource_created_signal);
|
2008-10-08 12:48:46 -04:00
|
|
|
client->display = display;
|
|
|
|
|
client->source = wl_event_loop_add_fd(display->loop, fd,
|
|
|
|
|
WL_EVENT_READABLE,
|
|
|
|
|
wl_client_connection_data, client);
|
2012-02-18 00:29:25 -05:00
|
|
|
|
2012-10-16 20:32:19 +02:00
|
|
|
if (!client->source)
|
|
|
|
|
goto err_client;
|
|
|
|
|
|
2021-03-15 22:21:12 +00:00
|
|
|
if (wl_os_socket_peercred(fd, &client->uid, &client->gid,
|
|
|
|
|
&client->pid) != 0)
|
2012-10-16 20:32:19 +02:00
|
|
|
goto err_source;
|
2012-02-18 00:29:25 -05:00
|
|
|
|
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
2021-09-25 22:34:44 -04:00
|
|
|
client->connection = wl_connection_create(fd, display->max_buffer_size);
|
|
|
|
|
|
2012-10-16 20:32:19 +02:00
|
|
|
if (client->connection == NULL)
|
|
|
|
|
goto err_source;
|
2008-12-21 22:45:33 -05:00
|
|
|
|
2013-06-01 17:40:52 -05:00
|
|
|
wl_map_init(&client->objects, WL_MAP_SERVER_SIDE);
|
2011-08-19 22:50:53 -04:00
|
|
|
|
2013-06-01 17:40:53 -05:00
|
|
|
if (wl_map_insert_at(&client->objects, 0, 0, NULL) < 0)
|
2012-10-16 20:32:19 +02:00
|
|
|
goto err_map;
|
2011-08-19 11:06:37 -04:00
|
|
|
|
2017-01-24 16:34:29 +02:00
|
|
|
wl_priv_signal_init(&client->destroy_signal);
|
2022-07-21 11:07:04 +01:00
|
|
|
wl_priv_signal_init(&client->destroy_late_signal);
|
2014-08-07 09:55:49 -04:00
|
|
|
if (bind_display(client, display) < 0)
|
2012-10-16 20:32:19 +02:00
|
|
|
goto err_map;
|
|
|
|
|
|
2011-06-14 10:35:46 +02:00
|
|
|
wl_list_insert(display->client_list.prev, &client->link);
|
|
|
|
|
|
2017-01-24 16:34:28 +02:00
|
|
|
wl_priv_signal_emit(&display->create_client_signal, client);
|
2016-08-09 12:46:51 +02:00
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
return client;
|
2012-10-16 20:32:19 +02:00
|
|
|
|
|
|
|
|
err_map:
|
|
|
|
|
wl_map_release(&client->objects);
|
|
|
|
|
wl_connection_destroy(client->connection);
|
|
|
|
|
err_source:
|
|
|
|
|
wl_event_source_remove(client->source);
|
|
|
|
|
err_client:
|
|
|
|
|
free(client);
|
|
|
|
|
return NULL;
|
2008-10-08 12:48:46 -04:00
|
|
|
}
|
|
|
|
|
|
2013-11-13 21:11:17 -08:00
|
|
|
/** Return Unix credentials for the client
|
|
|
|
|
*
|
|
|
|
|
* \param client The display object
|
|
|
|
|
* \param pid Returns the process ID
|
|
|
|
|
* \param uid Returns the user ID
|
|
|
|
|
* \param gid Returns the group ID
|
|
|
|
|
*
|
|
|
|
|
* This function returns the process ID, the user ID and the group ID
|
|
|
|
|
* for the given client. The credentials come from getsockopt() with
|
|
|
|
|
* SO_PEERCRED, on the client socket fd. All the pointers can be
|
|
|
|
|
* NULL, if the caller is not interested in a particular ID.
|
|
|
|
|
*
|
2022-05-31 19:23:38 +02:00
|
|
|
* Note, process IDs are subject to race conditions and are not a reliable way
|
|
|
|
|
* to identify a client.
|
|
|
|
|
*
|
2013-11-13 21:11:17 -08:00
|
|
|
* Be aware that for clients that a compositor forks and execs and
|
|
|
|
|
* then connects using socketpair(), this function will return the
|
|
|
|
|
* credentials for the compositor. The credentials for the socketpair
|
|
|
|
|
* are set at creation time in the compositor.
|
2015-01-26 11:30:57 -08:00
|
|
|
*
|
2013-11-13 21:11:17 -08:00
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
2012-02-18 00:29:25 -05:00
|
|
|
WL_EXPORT void
|
2023-07-06 18:18:37 +02:00
|
|
|
wl_client_get_credentials(const struct wl_client *client,
|
2012-02-18 00:29:25 -05:00
|
|
|
pid_t *pid, uid_t *uid, gid_t *gid)
|
|
|
|
|
{
|
|
|
|
|
if (pid)
|
2021-03-15 22:21:12 +00:00
|
|
|
*pid = client->pid;
|
2012-02-18 00:29:25 -05:00
|
|
|
if (uid)
|
2021-03-15 22:21:12 +00:00
|
|
|
*uid = client->uid;
|
2012-02-18 00:29:25 -05:00
|
|
|
if (gid)
|
2021-03-15 22:21:12 +00:00
|
|
|
*gid = client->gid;
|
2012-02-18 00:29:25 -05:00
|
|
|
}
|
|
|
|
|
|
2016-01-14 16:03:43 +09:00
|
|
|
/** Get the file descriptor for the client
|
|
|
|
|
*
|
|
|
|
|
* \param client The display object
|
|
|
|
|
* \return The file descriptor to use for the connection
|
|
|
|
|
*
|
|
|
|
|
* This function returns the file descriptor for the given client.
|
|
|
|
|
*
|
|
|
|
|
* Be sure to use the file descriptor from the client for inspection only.
|
|
|
|
|
* If the caller does anything to the file descriptor that changes its state,
|
|
|
|
|
* it will likely cause problems.
|
|
|
|
|
*
|
|
|
|
|
* See also wl_client_get_credentials().
|
|
|
|
|
* It is recommended that you evaluate whether wl_client_get_credentials()
|
|
|
|
|
* can be applied to your use case instead of this function.
|
|
|
|
|
*
|
|
|
|
|
* If you would like to distinguish just between the client and the compositor
|
|
|
|
|
* itself from the client's request, it can be done by getting the client
|
|
|
|
|
* credentials and by checking the PID of the client and the compositor's PID.
|
|
|
|
|
* Regarding the case in which the socketpair() is being used, you need to be
|
|
|
|
|
* careful. Please note the documentation for wl_client_get_credentials().
|
|
|
|
|
*
|
|
|
|
|
* This function can be used for a compositor to validate a request from
|
|
|
|
|
* a client if there are additional information provided from the client's
|
|
|
|
|
* file descriptor. For instance, suppose you can get the security contexts
|
|
|
|
|
* from the client's file descriptor. The compositor can validate the client's
|
|
|
|
|
* request with the contexts and make a decision whether it permits or deny it.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT int
|
|
|
|
|
wl_client_get_fd(struct wl_client *client)
|
|
|
|
|
{
|
|
|
|
|
return wl_connection_get_fd(client->connection);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-13 21:11:17 -08:00
|
|
|
/** Look up an object in the client name space
|
|
|
|
|
*
|
|
|
|
|
* \param client The client object
|
|
|
|
|
* \param id The object id
|
|
|
|
|
* \return The object or NULL if there is not object for the given ID
|
|
|
|
|
*
|
|
|
|
|
* This looks up an object in the client object name space by its
|
2015-01-26 11:30:57 -08:00
|
|
|
* object ID.
|
|
|
|
|
*
|
2013-11-13 21:11:17 -08:00
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
2012-04-27 11:28:06 -04:00
|
|
|
WL_EXPORT struct wl_resource *
|
|
|
|
|
wl_client_get_object(struct wl_client *client, uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
return wl_map_lookup(&client->objects, id);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-02 15:39:03 -04:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_client_post_no_memory(struct wl_client *client)
|
|
|
|
|
{
|
|
|
|
|
wl_resource_post_error(client->display_resource,
|
|
|
|
|
WL_DISPLAY_ERROR_NO_MEMORY, "no memory");
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-20 18:02:50 +11:00
|
|
|
/** Report an internal server error
|
|
|
|
|
*
|
|
|
|
|
* \param client The client object
|
|
|
|
|
* \param msg A printf-style format string
|
|
|
|
|
* \param ... Format string arguments
|
|
|
|
|
*
|
|
|
|
|
* Report an unspecified internal implementation error and disconnect
|
|
|
|
|
* the client.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_client_post_implementation_error(struct wl_client *client,
|
|
|
|
|
char const *msg, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
va_start(ap, msg);
|
|
|
|
|
wl_resource_post_error_vargs(client->display_resource,
|
|
|
|
|
WL_DISPLAY_ERROR_IMPLEMENTATION,
|
|
|
|
|
msg, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-02 20:55:16 -04:00
|
|
|
WL_EXPORT void
|
2011-09-01 09:53:33 -04:00
|
|
|
wl_resource_post_no_memory(struct wl_resource *resource)
|
2010-09-02 20:55:16 -04:00
|
|
|
{
|
2011-09-01 09:53:33 -04:00
|
|
|
wl_resource_post_error(resource->client->display_resource,
|
|
|
|
|
WL_DISPLAY_ERROR_NO_MEMORY, "no memory");
|
2010-09-02 20:55:16 -04:00
|
|
|
}
|
|
|
|
|
|
2017-01-24 16:34:30 +02:00
|
|
|
/** Detect if a wl_resource uses the deprecated public definition.
|
|
|
|
|
*
|
|
|
|
|
* Before Wayland 1.2.0, the definition of struct wl_resource was public.
|
|
|
|
|
* It was made opaque just before 1.2.0, and later new fields were added.
|
|
|
|
|
* The new fields cannot be accessed if a program is using the deprecated
|
2020-12-17 15:42:10 -05:00
|
|
|
* definition, as there would not be memory allocated for them.
|
2017-01-24 16:34:30 +02:00
|
|
|
*
|
|
|
|
|
* The creation pattern for the deprecated definition was wl_resource_init()
|
|
|
|
|
* followed by wl_client_add_resource(). wl_resource_init() was an inline
|
|
|
|
|
* function and no longer exists, but binaries might still carry it.
|
2020-12-17 15:42:10 -05:00
|
|
|
* wl_client_add_resource() still exists for ABI compatibility.
|
2017-01-24 16:34:30 +02:00
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
resource_is_deprecated(struct wl_resource *resource)
|
|
|
|
|
{
|
|
|
|
|
struct wl_map *map = &resource->client->objects;
|
|
|
|
|
int id = resource->object.id;
|
|
|
|
|
|
|
|
|
|
/* wl_client_add_resource() marks deprecated resources with the flag. */
|
|
|
|
|
if (wl_map_lookup_flags(map, id) & WL_MAP_ENTRY_LEGACY)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-08 00:36:10 +00:00
|
|
|
/** 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.
|
|
|
|
|
*/
|
2016-08-11 17:23:10 +02:00
|
|
|
static enum wl_iterator_result
|
2024-01-08 00:36:10 +00:00
|
|
|
remove_and_destroy_resource(void *element, void *data, uint32_t flags)
|
2011-08-19 17:07:14 -04:00
|
|
|
{
|
|
|
|
|
struct wl_resource *resource = element;
|
2024-01-08 00:36:10 +00:00
|
|
|
struct wl_client *client = resource->client;
|
|
|
|
|
uint32_t id = resource->object.id;;
|
2011-08-19 17:07:14 -04:00
|
|
|
|
2017-01-24 16:34:30 +02:00
|
|
|
wl_signal_emit(&resource->deprecated_destroy_signal, resource);
|
|
|
|
|
/* Don't emit the new signal for deprecated resources, as that would
|
|
|
|
|
* access memory outside the bounds of the deprecated struct */
|
|
|
|
|
if (!resource_is_deprecated(resource))
|
2018-04-16 15:00:59 -05:00
|
|
|
wl_priv_signal_final_emit(&resource->destroy_signal, resource);
|
2011-08-19 17:07:14 -04:00
|
|
|
|
|
|
|
|
if (resource->destroy)
|
|
|
|
|
resource->destroy(resource);
|
2013-07-02 16:59:44 -04:00
|
|
|
|
2024-01-08 00:36:10 +00:00
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-02 16:59:44 -04:00
|
|
|
if (!(flags & WL_MAP_ENTRY_LEGACY))
|
|
|
|
|
free(resource);
|
2016-08-11 17:23:10 +02:00
|
|
|
|
|
|
|
|
return WL_ITERATOR_CONTINUE;
|
2011-08-19 17:07:14 -04:00
|
|
|
}
|
|
|
|
|
|
2010-08-09 14:43:33 -04:00
|
|
|
WL_EXPORT void
|
Switch protocol to using serial numbers for ordering events and requests
The wayland protocol, as X, uses timestamps to match up certain
requests with input events. The problem is that sometimes we need to
send out an event that doesn't have a corresponding timestamped input
event. For example, the pointer focus surface goes away and new
surface needs to receive a pointer enter event. These events are
normally timestamped with the evdev event timestamp, but in this case,
we don't have a evdev timestamp. So we have to go to gettimeofday (or
clock_gettime()) and then we don't know if it's coming from the same
time source etc.
However for all these cases we don't need a real time timestamp, we
just need a serial number that encodes the order of events inside the
server. So we introduce a serial number mechanism that we can use to
order events. We still need real-time timestamps for actual input
device events (motion, buttons, keys, touch), to be able to reason
about double-click speed and movement speed so events that correspond to user input carry both a serial number and a timestamp.
The serial number also give us a mechanism to key together events that
are "logically the same" such as a unicode event and a keycode event,
or a motion event and a relative event from a raw device.
2012-04-11 22:25:51 -04:00
|
|
|
wl_resource_destroy(struct wl_resource *resource)
|
2008-12-15 20:35:24 -05:00
|
|
|
{
|
2011-08-19 11:06:37 -04:00
|
|
|
struct wl_client *client = resource->client;
|
2024-01-08 00:36:10 +00:00
|
|
|
uint32_t flags = wl_map_lookup_flags(&client->objects, resource->object.id);
|
2011-05-06 17:09:51 +02:00
|
|
|
|
2024-01-08 00:36:10 +00:00
|
|
|
remove_and_destroy_resource(resource, NULL, flags);
|
2008-12-15 20:35:24 -05:00
|
|
|
}
|
|
|
|
|
|
2013-06-07 01:00:30 -04:00
|
|
|
WL_EXPORT uint32_t
|
2023-07-06 18:18:37 +02:00
|
|
|
wl_resource_get_id(const struct wl_resource *resource)
|
2013-06-07 01:00:30 -04:00
|
|
|
{
|
|
|
|
|
return resource->object.id;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-01 17:40:54 -05:00
|
|
|
WL_EXPORT struct wl_list *
|
|
|
|
|
wl_resource_get_link(struct wl_resource *resource)
|
|
|
|
|
{
|
|
|
|
|
return &resource->link;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-14 10:07:52 -05:00
|
|
|
WL_EXPORT struct wl_resource *
|
|
|
|
|
wl_resource_from_link(struct wl_list *link)
|
|
|
|
|
{
|
2014-02-04 14:21:48 +00:00
|
|
|
struct wl_resource *resource;
|
2013-06-14 10:07:52 -05:00
|
|
|
|
|
|
|
|
return wl_container_of(link, resource, link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WL_EXPORT struct wl_resource *
|
|
|
|
|
wl_resource_find_for_client(struct wl_list *list, struct wl_client *client)
|
|
|
|
|
{
|
|
|
|
|
struct wl_resource *resource;
|
|
|
|
|
|
|
|
|
|
if (client == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2015-01-26 11:30:57 -08:00
|
|
|
wl_list_for_each(resource, list, link) {
|
|
|
|
|
if (resource->client == client)
|
|
|
|
|
return resource;
|
|
|
|
|
}
|
2013-06-14 10:07:52 -05:00
|
|
|
|
2015-01-26 11:30:57 -08:00
|
|
|
return NULL;
|
2013-06-14 10:07:52 -05:00
|
|
|
}
|
|
|
|
|
|
2013-06-01 17:40:54 -05:00
|
|
|
WL_EXPORT struct wl_client *
|
|
|
|
|
wl_resource_get_client(struct wl_resource *resource)
|
|
|
|
|
{
|
|
|
|
|
return resource->client;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-14 10:07:52 -05:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_resource_set_user_data(struct wl_resource *resource, void *data)
|
|
|
|
|
{
|
|
|
|
|
resource->data = data;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-01 17:40:54 -05:00
|
|
|
WL_EXPORT void *
|
|
|
|
|
wl_resource_get_user_data(struct wl_resource *resource)
|
|
|
|
|
{
|
|
|
|
|
return resource->data;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 20:09:20 -05:00
|
|
|
WL_EXPORT int
|
2023-07-06 18:18:37 +02:00
|
|
|
wl_resource_get_version(const struct wl_resource *resource)
|
2013-06-27 20:09:20 -05:00
|
|
|
{
|
|
|
|
|
return resource->version;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-01 17:40:54 -05:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_resource_set_destructor(struct wl_resource *resource,
|
|
|
|
|
wl_resource_destroy_func_t destroy)
|
|
|
|
|
{
|
|
|
|
|
resource->destroy = destroy;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-20 20:36:47 -05:00
|
|
|
WL_EXPORT int
|
|
|
|
|
wl_resource_instance_of(struct wl_resource *resource,
|
|
|
|
|
const struct wl_interface *interface,
|
|
|
|
|
const void *implementation)
|
|
|
|
|
{
|
|
|
|
|
return wl_interface_equal(resource->object.interface, interface) &&
|
|
|
|
|
resource->object.implementation == implementation;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-01 17:40:54 -05:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_resource_add_destroy_listener(struct wl_resource *resource,
|
|
|
|
|
struct wl_listener * listener)
|
|
|
|
|
{
|
2017-01-24 16:34:30 +02:00
|
|
|
if (resource_is_deprecated(resource))
|
|
|
|
|
wl_signal_add(&resource->deprecated_destroy_signal, listener);
|
|
|
|
|
else
|
|
|
|
|
wl_priv_signal_add(&resource->destroy_signal, listener);
|
2013-06-01 17:40:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WL_EXPORT struct wl_listener *
|
|
|
|
|
wl_resource_get_destroy_listener(struct wl_resource *resource,
|
|
|
|
|
wl_notify_func_t notify)
|
|
|
|
|
{
|
2017-01-24 16:34:30 +02:00
|
|
|
if (resource_is_deprecated(resource))
|
|
|
|
|
return wl_signal_get(&resource->deprecated_destroy_signal, notify);
|
|
|
|
|
return wl_priv_signal_get(&resource->destroy_signal, notify);
|
2013-06-01 17:40:54 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-09 12:46:52 +02:00
|
|
|
/** Retrieve the interface name (class) of a resource object.
|
|
|
|
|
*
|
|
|
|
|
* \param resource The resource object
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_resource
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT const char *
|
2023-07-06 18:18:37 +02:00
|
|
|
wl_resource_get_class(const struct wl_resource *resource)
|
2016-08-09 12:46:52 +02:00
|
|
|
{
|
|
|
|
|
return resource->object.interface->name;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-06 23:48:57 +02:00
|
|
|
/** 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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-21 11:07:04 +01:00
|
|
|
/**
|
|
|
|
|
* Add a listener to be called at the beginning of wl_client destruction
|
|
|
|
|
*
|
|
|
|
|
* The listener provided will be called when wl_client destroy has begun,
|
|
|
|
|
* before any of that client's resources have been destroyed.
|
|
|
|
|
*
|
|
|
|
|
* There is no requirement to remove the link of the wl_listener when the
|
|
|
|
|
* signal is emitted.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
2012-04-13 09:53:15 -04:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_client_add_destroy_listener(struct wl_client *client,
|
|
|
|
|
struct wl_listener *listener)
|
|
|
|
|
{
|
2017-01-24 16:34:29 +02:00
|
|
|
wl_priv_signal_add(&client->destroy_signal, listener);
|
2012-04-13 09:53:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WL_EXPORT struct wl_listener *
|
|
|
|
|
wl_client_get_destroy_listener(struct wl_client *client,
|
|
|
|
|
wl_notify_func_t notify)
|
|
|
|
|
{
|
2017-01-24 16:34:29 +02:00
|
|
|
return wl_priv_signal_get(&client->destroy_signal, notify);
|
2012-04-13 09:53:15 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-21 11:07:04 +01:00
|
|
|
/**
|
|
|
|
|
* Add a listener to be called at the end of wl_client destruction
|
|
|
|
|
*
|
|
|
|
|
* The listener provided will be called when wl_client destroy is nearly
|
|
|
|
|
* complete, after all of that client's resources have been destroyed.
|
|
|
|
|
*
|
|
|
|
|
* There is no requirement to remove the link of the wl_listener when the
|
|
|
|
|
* signal is emitted.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_client
|
|
|
|
|
* \since 1.22.0
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_client_add_destroy_late_listener(struct wl_client *client,
|
|
|
|
|
struct wl_listener *listener)
|
|
|
|
|
{
|
|
|
|
|
wl_priv_signal_add(&client->destroy_late_signal, listener);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WL_EXPORT struct wl_listener *
|
|
|
|
|
wl_client_get_destroy_late_listener(struct wl_client *client,
|
|
|
|
|
wl_notify_func_t notify)
|
|
|
|
|
{
|
|
|
|
|
return wl_priv_signal_get(&client->destroy_late_signal, notify);
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-05 17:44:31 -04:00
|
|
|
WL_EXPORT void
|
2008-10-08 12:48:46 -04:00
|
|
|
wl_client_destroy(struct wl_client *client)
|
|
|
|
|
{
|
2024-01-05 00:50:49 +00:00
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
2018-04-16 15:00:59 -05:00
|
|
|
wl_priv_signal_final_emit(&client->destroy_signal, client);
|
2012-04-13 09:53:15 -04:00
|
|
|
|
2011-08-29 15:01:41 -04:00
|
|
|
wl_client_flush(client);
|
2024-01-08 00:36:10 +00:00
|
|
|
wl_map_for_each(&client->objects, remove_and_destroy_resource, NULL);
|
2011-08-19 22:50:53 -04:00
|
|
|
wl_map_release(&client->objects);
|
2008-11-28 18:35:25 -05:00
|
|
|
wl_event_source_remove(client->source);
|
2014-09-30 14:43:03 +02:00
|
|
|
close(wl_connection_destroy(client->connection));
|
2022-07-21 11:07:04 +01:00
|
|
|
|
|
|
|
|
wl_priv_signal_final_emit(&client->destroy_late_signal, client);
|
|
|
|
|
|
2016-08-11 17:23:09 +02:00
|
|
|
wl_list_remove(&client->resource_created_signal.listener_list);
|
2021-10-25 04:34:49 +02:00
|
|
|
|
|
|
|
|
if (client->data_dtor)
|
|
|
|
|
client->data_dtor(client->data);
|
|
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
free(client);
|
2008-09-30 09:46:10 -04:00
|
|
|
}
|
|
|
|
|
|
2016-10-18 16:23:39 +02:00
|
|
|
/* Check if a global filter is registered and use it if any.
|
|
|
|
|
*
|
2020-12-17 15:42:10 -05:00
|
|
|
* If no wl_global filter has been registered, this function will
|
2016-10-18 16:23:39 +02:00
|
|
|
* return true, allowing the wl_global to be visible to the wl_client
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
wl_global_is_visible(const struct wl_client *client,
|
|
|
|
|
const struct wl_global *global)
|
|
|
|
|
{
|
|
|
|
|
struct wl_display *display = client->display;
|
|
|
|
|
|
|
|
|
|
return (display->global_filter == NULL ||
|
|
|
|
|
display->global_filter(client, global, display->global_filter_data));
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-14 10:38:44 -04:00
|
|
|
static void
|
2012-10-08 13:53:47 -04:00
|
|
|
registry_bind(struct wl_client *client,
|
|
|
|
|
struct wl_resource *resource, uint32_t name,
|
|
|
|
|
const char *interface, uint32_t version, uint32_t id)
|
2011-04-14 10:38:44 -04:00
|
|
|
{
|
|
|
|
|
struct wl_global *global;
|
2011-08-18 17:53:50 -04:00
|
|
|
struct wl_display *display = resource->data;
|
2011-04-14 10:38:44 -04:00
|
|
|
|
|
|
|
|
wl_list_for_each(global, &display->global_list, link)
|
2011-08-19 16:57:48 -04:00
|
|
|
if (global->name == name)
|
2011-05-12 21:27:57 -04:00
|
|
|
break;
|
|
|
|
|
|
2013-11-12 21:44:37 -05:00
|
|
|
if (&global->link == &display->global_list)
|
2011-09-01 09:53:33 -04:00
|
|
|
wl_resource_post_error(resource,
|
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
2013-11-12 21:44:37 -05:00
|
|
|
"invalid global %s (%d)", interface, name);
|
2019-08-28 17:26:52 +03:00
|
|
|
else if (strcmp(global->interface->name, interface) != 0)
|
|
|
|
|
wl_resource_post_error(resource,
|
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
|
"invalid interface for global %u: "
|
|
|
|
|
"have %s, wanted %s",
|
|
|
|
|
name, interface, global->interface->name);
|
2016-01-14 13:33:52 -06:00
|
|
|
else if (version == 0)
|
|
|
|
|
wl_resource_post_error(resource,
|
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
|
"invalid version for global %s (%d): 0 is not a valid version",
|
|
|
|
|
interface, name);
|
2013-11-12 21:44:37 -05:00
|
|
|
else if (global->version < version)
|
|
|
|
|
wl_resource_post_error(resource,
|
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
|
"invalid version for global %s (%d): have %d, wanted %d",
|
|
|
|
|
interface, name, global->version, version);
|
2016-10-18 16:23:39 +02:00
|
|
|
else if (!wl_global_is_visible(client, global))
|
|
|
|
|
wl_resource_post_error(resource,
|
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
|
"invalid global %s (%d)", interface, name);
|
2011-08-19 16:57:48 -04:00
|
|
|
else
|
|
|
|
|
global->bind(client, global->data, version, id);
|
2011-04-14 10:38:44 -04:00
|
|
|
}
|
|
|
|
|
|
2012-10-08 13:53:47 -04:00
|
|
|
static const struct wl_registry_interface registry_interface = {
|
|
|
|
|
registry_bind
|
|
|
|
|
};
|
|
|
|
|
|
2010-09-03 14:46:38 -04:00
|
|
|
static void
|
|
|
|
|
display_sync(struct wl_client *client,
|
2011-08-18 17:53:50 -04:00
|
|
|
struct wl_resource *resource, uint32_t id)
|
2010-09-03 14:46:38 -04:00
|
|
|
{
|
2011-08-19 22:50:53 -04:00
|
|
|
struct wl_resource *callback;
|
Switch protocol to using serial numbers for ordering events and requests
The wayland protocol, as X, uses timestamps to match up certain
requests with input events. The problem is that sometimes we need to
send out an event that doesn't have a corresponding timestamped input
event. For example, the pointer focus surface goes away and new
surface needs to receive a pointer enter event. These events are
normally timestamped with the evdev event timestamp, but in this case,
we don't have a evdev timestamp. So we have to go to gettimeofday (or
clock_gettime()) and then we don't know if it's coming from the same
time source etc.
However for all these cases we don't need a real time timestamp, we
just need a serial number that encodes the order of events inside the
server. So we introduce a serial number mechanism that we can use to
order events. We still need real-time timestamps for actual input
device events (motion, buttons, keys, touch), to be able to reason
about double-click speed and movement speed so events that correspond to user input carry both a serial number and a timestamp.
The serial number also give us a mechanism to key together events that
are "logically the same" such as a unicode event and a keycode event,
or a motion event and a relative event from a raw device.
2012-04-11 22:25:51 -04:00
|
|
|
uint32_t serial;
|
2010-09-03 14:46:38 -04:00
|
|
|
|
2013-06-27 20:09:20 -05:00
|
|
|
callback = wl_resource_create(client, &wl_callback_interface, 1, id);
|
2013-07-02 15:39:03 -04:00
|
|
|
if (callback == NULL) {
|
|
|
|
|
wl_client_post_no_memory(client);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
Switch protocol to using serial numbers for ordering events and requests
The wayland protocol, as X, uses timestamps to match up certain
requests with input events. The problem is that sometimes we need to
send out an event that doesn't have a corresponding timestamped input
event. For example, the pointer focus surface goes away and new
surface needs to receive a pointer enter event. These events are
normally timestamped with the evdev event timestamp, but in this case,
we don't have a evdev timestamp. So we have to go to gettimeofday (or
clock_gettime()) and then we don't know if it's coming from the same
time source etc.
However for all these cases we don't need a real time timestamp, we
just need a serial number that encodes the order of events inside the
server. So we introduce a serial number mechanism that we can use to
order events. We still need real-time timestamps for actual input
device events (motion, buttons, keys, touch), to be able to reason
about double-click speed and movement speed so events that correspond to user input carry both a serial number and a timestamp.
The serial number also give us a mechanism to key together events that
are "logically the same" such as a unicode event and a keycode event,
or a motion event and a relative event from a raw device.
2012-04-11 22:25:51 -04:00
|
|
|
serial = wl_display_get_serial(client->display);
|
|
|
|
|
wl_callback_send_done(callback, serial);
|
|
|
|
|
wl_resource_destroy(callback);
|
2010-09-03 14:46:38 -04:00
|
|
|
}
|
|
|
|
|
|
2012-10-08 13:53:47 -04:00
|
|
|
static void
|
|
|
|
|
unbind_resource(struct wl_resource *resource)
|
|
|
|
|
{
|
|
|
|
|
wl_list_remove(&resource->link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
display_get_registry(struct wl_client *client,
|
|
|
|
|
struct wl_resource *resource, uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
struct wl_display *display = resource->data;
|
|
|
|
|
struct wl_resource *registry_resource;
|
|
|
|
|
struct wl_global *global;
|
|
|
|
|
|
|
|
|
|
registry_resource =
|
2013-06-27 20:09:20 -05:00
|
|
|
wl_resource_create(client, &wl_registry_interface, 1, id);
|
2013-07-02 15:39:03 -04:00
|
|
|
if (registry_resource == NULL) {
|
|
|
|
|
wl_client_post_no_memory(client);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 20:09:20 -05:00
|
|
|
wl_resource_set_implementation(registry_resource,
|
|
|
|
|
®istry_interface,
|
|
|
|
|
display, unbind_resource);
|
2012-10-08 13:53:47 -04:00
|
|
|
|
|
|
|
|
wl_list_insert(&display->registry_resource_list,
|
|
|
|
|
®istry_resource->link);
|
|
|
|
|
|
|
|
|
|
wl_list_for_each(global, &display->global_list, link)
|
2019-07-20 23:36:29 +03:00
|
|
|
if (wl_global_is_visible(client, global) && !global->removed)
|
2016-10-18 16:23:39 +02:00
|
|
|
wl_resource_post_event(registry_resource,
|
|
|
|
|
WL_REGISTRY_GLOBAL,
|
|
|
|
|
global->name,
|
|
|
|
|
global->interface->name,
|
|
|
|
|
global->version);
|
2012-10-08 13:53:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_display_interface display_interface = {
|
2010-09-03 14:46:38 -04:00
|
|
|
display_sync,
|
2012-10-08 13:53:47 -04:00
|
|
|
display_get_registry
|
2010-09-03 14:46:38 -04:00
|
|
|
};
|
|
|
|
|
|
2011-11-28 09:47:15 +02:00
|
|
|
static void
|
|
|
|
|
destroy_client_display_resource(struct wl_resource *resource)
|
|
|
|
|
{
|
|
|
|
|
resource->client->display_resource = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-07 09:55:49 -04:00
|
|
|
static int
|
|
|
|
|
bind_display(struct wl_client *client, struct wl_display *display)
|
2011-08-19 16:57:48 -04:00
|
|
|
{
|
|
|
|
|
client->display_resource =
|
2014-08-07 09:55:49 -04:00
|
|
|
wl_resource_create(client, &wl_display_interface, 1, 1);
|
2013-07-02 15:39:03 -04:00
|
|
|
if (client->display_resource == NULL) {
|
2016-01-11 11:45:12 +01:00
|
|
|
/* DON'T send no-memory error to client - it has no
|
|
|
|
|
* resource to which it could post the event */
|
2014-08-07 09:55:49 -04:00
|
|
|
return -1;
|
2013-07-02 15:39:03 -04:00
|
|
|
}
|
|
|
|
|
|
2013-06-27 20:09:20 -05:00
|
|
|
wl_resource_set_implementation(client->display_resource,
|
|
|
|
|
&display_interface, display,
|
|
|
|
|
destroy_client_display_resource);
|
2014-08-07 09:55:49 -04:00
|
|
|
return 0;
|
2011-08-19 16:57:48 -04:00
|
|
|
}
|
2010-09-03 14:46:38 -04:00
|
|
|
|
2021-08-31 18:59:33 +09:00
|
|
|
static int
|
|
|
|
|
handle_display_terminate(int fd, uint32_t mask, void *data) {
|
|
|
|
|
uint64_t term_event;
|
|
|
|
|
|
|
|
|
|
if (read(fd, &term_event, sizeof(term_event)) < 0 && errno != EAGAIN)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-07 09:37:45 +05:30
|
|
|
/** Create Wayland display object.
|
|
|
|
|
*
|
|
|
|
|
* \return The Wayland display object. Null if failed to create
|
|
|
|
|
*
|
|
|
|
|
* This creates the wl_display object.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
2008-12-05 11:13:50 -05:00
|
|
|
WL_EXPORT struct wl_display *
|
2008-09-30 09:46:10 -04:00
|
|
|
wl_display_create(void)
|
|
|
|
|
{
|
|
|
|
|
struct wl_display *display;
|
2010-09-07 10:58:19 -04:00
|
|
|
const char *debug;
|
2025-05-27 22:40:14 +01:00
|
|
|
const char *no_color;
|
|
|
|
|
const char *force_color;
|
2010-09-07 10:58:19 -04:00
|
|
|
|
2025-05-27 22:40:14 +01:00
|
|
|
no_color = getenv("NO_COLOR");
|
|
|
|
|
force_color = getenv("FORCE_COLOR");
|
2010-09-07 10:58:19 -04:00
|
|
|
debug = getenv("WAYLAND_DEBUG");
|
2024-09-17 17:27:37 -06:00
|
|
|
if (debug && (wl_check_env_token(debug, "server") || wl_check_env_token(debug, "1"))) {
|
2013-12-18 20:56:18 -06:00
|
|
|
debug_server = 1;
|
2025-05-27 22:40:14 +01:00
|
|
|
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;
|
2008-09-30 09:46:10 -04:00
|
|
|
|
2022-01-31 22:23:30 +01:00
|
|
|
display = zalloc(sizeof *display);
|
2008-09-30 09:46:10 -04:00
|
|
|
if (display == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
display->loop = wl_event_loop_create();
|
|
|
|
|
if (display->loop == NULL) {
|
|
|
|
|
free(display);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 18:59:33 +09:00
|
|
|
display->terminate_efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
|
|
|
|
if (display->terminate_efd < 0)
|
|
|
|
|
goto err_eventfd;
|
|
|
|
|
|
|
|
|
|
display->term_source = wl_event_loop_add_fd(display->loop,
|
|
|
|
|
display->terminate_efd,
|
|
|
|
|
WL_EVENT_READABLE,
|
|
|
|
|
handle_display_terminate,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
if (display->term_source == NULL)
|
|
|
|
|
goto err_term_source;
|
|
|
|
|
|
2008-11-23 19:10:23 -05:00
|
|
|
wl_list_init(&display->global_list);
|
2010-12-01 15:36:20 -05:00
|
|
|
wl_list_init(&display->socket_list);
|
2011-06-14 10:35:46 +02:00
|
|
|
wl_list_init(&display->client_list);
|
2012-10-08 13:53:47 -04:00
|
|
|
wl_list_init(&display->registry_resource_list);
|
2016-08-12 09:33:06 +02:00
|
|
|
wl_list_init(&display->protocol_loggers);
|
2008-11-02 10:12:29 -05:00
|
|
|
|
2017-01-24 16:34:28 +02:00
|
|
|
wl_priv_signal_init(&display->destroy_signal);
|
|
|
|
|
wl_priv_signal_init(&display->create_client_signal);
|
2013-01-11 14:29:32 -06:00
|
|
|
|
2023-01-24 23:55:29 +01:00
|
|
|
display->next_global_name = 1;
|
2012-05-22 18:48:13 +01:00
|
|
|
display->serial = 0;
|
2011-08-18 17:53:50 -04:00
|
|
|
|
2016-10-18 16:23:39 +02:00
|
|
|
display->global_filter = NULL;
|
|
|
|
|
display->global_filter_data = NULL;
|
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
2021-09-25 22:34:44 -04:00
|
|
|
display->max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE;
|
2016-10-18 16:23:39 +02:00
|
|
|
|
2013-08-06 20:05:53 +02:00
|
|
|
wl_array_init(&display->additional_shm_formats);
|
|
|
|
|
|
2010-09-03 14:46:38 -04:00
|
|
|
return display;
|
2021-08-31 18:59:33 +09:00
|
|
|
|
|
|
|
|
err_term_source:
|
|
|
|
|
close(display->terminate_efd);
|
|
|
|
|
err_eventfd:
|
|
|
|
|
wl_event_loop_destroy(display->loop);
|
|
|
|
|
free(display);
|
|
|
|
|
return NULL;
|
2008-09-30 09:46:10 -04:00
|
|
|
}
|
|
|
|
|
|
2014-05-08 10:22:25 -04:00
|
|
|
static void
|
|
|
|
|
wl_socket_destroy(struct wl_socket *s)
|
|
|
|
|
{
|
|
|
|
|
if (s->source)
|
|
|
|
|
wl_event_source_remove(s->source);
|
|
|
|
|
if (s->addr.sun_path[0])
|
|
|
|
|
unlink(s->addr.sun_path);
|
2014-08-07 16:46:52 +03:00
|
|
|
if (s->fd >= 0)
|
2014-05-08 10:22:25 -04:00
|
|
|
close(s->fd);
|
|
|
|
|
if (s->lock_addr[0])
|
|
|
|
|
unlink(s->lock_addr);
|
2014-08-07 16:46:52 +03:00
|
|
|
if (s->fd_lock >= 0)
|
2014-05-08 10:22:25 -04:00
|
|
|
close(s->fd_lock);
|
|
|
|
|
|
|
|
|
|
free(s);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-07 16:46:52 +03:00
|
|
|
static struct wl_socket *
|
|
|
|
|
wl_socket_alloc(void)
|
|
|
|
|
{
|
|
|
|
|
struct wl_socket *s;
|
|
|
|
|
|
2015-08-26 12:00:06 +08:00
|
|
|
s = zalloc(sizeof *s);
|
2014-08-07 16:46:52 +03:00
|
|
|
if (!s)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
s->fd = -1;
|
|
|
|
|
s->fd_lock = -1;
|
|
|
|
|
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-15 14:51:27 +05:30
|
|
|
/** Destroy Wayland display object.
|
|
|
|
|
*
|
|
|
|
|
* \param display The Wayland display object which should be destroyed.
|
|
|
|
|
*
|
|
|
|
|
* This function emits the wl_display destroy signal, releases
|
|
|
|
|
* all the sockets added to this display, free's all the globals associated
|
|
|
|
|
* with this display, free's memory of additional shared memory formats and
|
|
|
|
|
* destroy the display object.
|
|
|
|
|
*
|
|
|
|
|
* \sa wl_display_add_destroy_listener
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
2010-12-01 15:36:20 -05:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_display_destroy(struct wl_display *display)
|
|
|
|
|
{
|
|
|
|
|
struct wl_socket *s, *next;
|
2011-06-14 11:41:54 +02:00
|
|
|
struct wl_global *global, *gnext;
|
2010-12-01 15:36:20 -05:00
|
|
|
|
2018-04-16 15:00:59 -05:00
|
|
|
wl_priv_signal_final_emit(&display->destroy_signal, display);
|
2013-01-11 14:29:32 -06:00
|
|
|
|
2010-12-01 15:36:20 -05:00
|
|
|
wl_list_for_each_safe(s, next, &display->socket_list, link) {
|
2014-05-08 10:22:25 -04:00
|
|
|
wl_socket_destroy(s);
|
2010-12-01 15:36:20 -05:00
|
|
|
}
|
2021-08-31 18:59:33 +09:00
|
|
|
|
|
|
|
|
close(display->terminate_efd);
|
|
|
|
|
wl_event_source_remove(display->term_source);
|
|
|
|
|
|
2011-12-22 16:52:37 +02:00
|
|
|
wl_event_loop_destroy(display->loop);
|
2010-12-01 15:36:20 -05:00
|
|
|
|
2011-06-14 11:41:54 +02:00
|
|
|
wl_list_for_each_safe(global, gnext, &display->global_list, link)
|
|
|
|
|
free(global);
|
|
|
|
|
|
2013-08-08 10:31:56 +02:00
|
|
|
wl_array_release(&display->additional_shm_formats);
|
|
|
|
|
|
2016-08-12 09:33:06 +02:00
|
|
|
wl_list_remove(&display->protocol_loggers);
|
|
|
|
|
|
2010-12-01 15:36:20 -05:00
|
|
|
free(display);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 16:23:39 +02:00
|
|
|
/** Set a filter function for global objects
|
|
|
|
|
*
|
|
|
|
|
* \param display The Wayland display object.
|
2020-12-17 15:42:10 -05:00
|
|
|
* \param filter The global filter function.
|
2016-10-18 16:23:39 +02:00
|
|
|
* \param data User data to be associated with the global filter.
|
|
|
|
|
*
|
|
|
|
|
* Set a filter for the wl_display to advertise or hide global objects
|
|
|
|
|
* to clients.
|
2020-12-17 15:42:10 -05:00
|
|
|
* The set filter will be used during wl_global advertisement to
|
2016-10-18 16:23:39 +02:00
|
|
|
* determine whether a global object should be advertised to a
|
|
|
|
|
* given client, and during wl_global binding to determine whether
|
|
|
|
|
* a given client should be allowed to bind to a global.
|
|
|
|
|
*
|
|
|
|
|
* Clients that try to bind to a global that was filtered out will
|
|
|
|
|
* have an error raised.
|
|
|
|
|
*
|
|
|
|
|
* Setting the filter NULL will result in all globals being
|
|
|
|
|
* advertised to all clients. The default is no filter.
|
|
|
|
|
*
|
2022-06-15 10:37:18 +02:00
|
|
|
* The filter should be installed before any client connects and should always
|
|
|
|
|
* take the same decision given a client and a global. Not doing so will result
|
|
|
|
|
* in inconsistent filtering and broken wl_registry event sequences.
|
|
|
|
|
*
|
2016-10-18 16:23:39 +02:00
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_display_set_global_filter(struct wl_display *display,
|
|
|
|
|
wl_display_global_filter_func_t filter,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
display->global_filter = filter;
|
|
|
|
|
display->global_filter_data = data;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-19 16:57:48 -04:00
|
|
|
WL_EXPORT struct wl_global *
|
2013-07-08 18:45:41 -04:00
|
|
|
wl_global_create(struct wl_display *display,
|
|
|
|
|
const struct wl_interface *interface, int version,
|
|
|
|
|
void *data, wl_global_bind_func_t bind)
|
2008-11-23 19:10:23 -05:00
|
|
|
{
|
2008-12-21 23:37:12 -05:00
|
|
|
struct wl_global *global;
|
2012-10-08 13:53:47 -04:00
|
|
|
struct wl_resource *resource;
|
2008-11-23 19:10:23 -05:00
|
|
|
|
2016-01-14 11:02:18 -06:00
|
|
|
if (version < 1) {
|
|
|
|
|
wl_log("wl_global_create: failing to create interface "
|
|
|
|
|
"'%s' with version %d because it is less than 1\n",
|
|
|
|
|
interface->name, version);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-14 11:02:17 -06:00
|
|
|
if (version > interface->version) {
|
|
|
|
|
wl_log("wl_global_create: implemented version for '%s' "
|
|
|
|
|
"higher than interface version (%d > %d)\n",
|
|
|
|
|
interface->name, version, interface->version);
|
2013-07-08 18:45:41 -04:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-24 23:55:29 +01:00
|
|
|
if (display->next_global_name >= UINT32_MAX) {
|
2023-01-24 23:51:57 +01:00
|
|
|
wl_log("wl_global_create: ran out of global names\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-31 22:23:30 +01:00
|
|
|
global = zalloc(sizeof *global);
|
2008-12-21 23:37:12 -05:00
|
|
|
if (global == NULL)
|
2011-08-19 16:57:48 -04:00
|
|
|
return NULL;
|
2008-11-23 19:10:23 -05:00
|
|
|
|
2013-07-08 18:45:41 -04:00
|
|
|
global->display = display;
|
2023-01-24 23:55:29 +01:00
|
|
|
global->name = display->next_global_name++;
|
2011-08-19 16:57:48 -04:00
|
|
|
global->interface = interface;
|
2013-07-08 18:45:41 -04:00
|
|
|
global->version = version;
|
2011-08-19 16:57:48 -04:00
|
|
|
global->data = data;
|
2011-08-19 11:05:01 -04:00
|
|
|
global->bind = bind;
|
2019-07-20 23:36:29 +03:00
|
|
|
global->removed = false;
|
2008-12-21 23:37:12 -05:00
|
|
|
wl_list_insert(display->global_list.prev, &global->link);
|
2008-11-23 19:10:23 -05:00
|
|
|
|
2012-10-08 13:53:47 -04:00
|
|
|
wl_list_for_each(resource, &display->registry_resource_list, link)
|
2022-05-12 19:29:11 +02:00
|
|
|
if (wl_global_is_visible(resource->client, global))
|
|
|
|
|
wl_resource_post_event(resource,
|
|
|
|
|
WL_REGISTRY_GLOBAL,
|
|
|
|
|
global->name,
|
|
|
|
|
global->interface->name,
|
|
|
|
|
global->version);
|
2012-05-02 08:46:47 +02:00
|
|
|
|
2011-08-19 16:57:48 -04:00
|
|
|
return global;
|
2008-11-23 19:10:23 -05:00
|
|
|
}
|
|
|
|
|
|
2019-07-20 23:36:29 +03:00
|
|
|
/** Remove the global
|
|
|
|
|
*
|
|
|
|
|
* \param global The Wayland global.
|
|
|
|
|
*
|
|
|
|
|
* Broadcast a global remove event to all clients without destroying the
|
|
|
|
|
* global. This function can only be called once per global.
|
|
|
|
|
*
|
|
|
|
|
* wl_global_destroy() removes the global and immediately destroys it. On
|
|
|
|
|
* the other end, this function only removes the global, allowing clients
|
|
|
|
|
* that have not yet received the global remove event to continue to bind to
|
|
|
|
|
* it.
|
|
|
|
|
*
|
|
|
|
|
* This can be used by compositors to mitigate clients being disconnected
|
|
|
|
|
* because a global has been added and removed too quickly. Compositors can call
|
|
|
|
|
* wl_global_remove(), then wait an implementation-defined amount of time, then
|
|
|
|
|
* call wl_global_destroy(). Note that the destruction of a global is still
|
|
|
|
|
* racy, since clients have no way to acknowledge that they received the remove
|
|
|
|
|
* event.
|
|
|
|
|
*
|
|
|
|
|
* \since 1.17.90
|
|
|
|
|
*/
|
2011-08-19 16:57:48 -04:00
|
|
|
WL_EXPORT void
|
2019-07-20 23:36:29 +03:00
|
|
|
wl_global_remove(struct wl_global *global)
|
2011-06-14 10:35:46 +02:00
|
|
|
{
|
2013-07-08 18:45:41 -04:00
|
|
|
struct wl_display *display = global->display;
|
2012-10-08 13:53:47 -04:00
|
|
|
struct wl_resource *resource;
|
2011-06-14 10:35:46 +02:00
|
|
|
|
2019-07-20 23:36:29 +03:00
|
|
|
if (global->removed)
|
|
|
|
|
wl_abort("wl_global_remove: called twice on the same "
|
2023-05-24 11:24:23 -07:00
|
|
|
"global '%s#%"PRIu32"'", global->interface->name,
|
2019-07-20 23:36:29 +03:00
|
|
|
global->name);
|
|
|
|
|
|
2012-10-08 13:53:47 -04:00
|
|
|
wl_list_for_each(resource, &display->registry_resource_list, link)
|
2022-05-12 19:29:11 +02:00
|
|
|
if (wl_global_is_visible(resource->client, global))
|
|
|
|
|
wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE,
|
|
|
|
|
global->name);
|
2019-07-20 23:36:29 +03:00
|
|
|
|
|
|
|
|
global->removed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_global_destroy(struct wl_global *global)
|
|
|
|
|
{
|
|
|
|
|
if (!global->removed)
|
|
|
|
|
wl_global_remove(global);
|
2011-06-14 10:35:46 +02:00
|
|
|
wl_list_remove(&global->link);
|
|
|
|
|
free(global);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 16:23:40 +02:00
|
|
|
WL_EXPORT const struct wl_interface *
|
|
|
|
|
wl_global_get_interface(const struct wl_global *global)
|
|
|
|
|
{
|
|
|
|
|
return global->interface;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-21 22:08:15 +00:00
|
|
|
/** Get the name of the global.
|
|
|
|
|
*
|
|
|
|
|
* \param global The global object.
|
|
|
|
|
* \param client Client for which to look up the global.
|
|
|
|
|
* \return The name of the global, or 0 if the global is not visible to the
|
|
|
|
|
* client.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_global
|
|
|
|
|
* \since 1.22
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT uint32_t
|
|
|
|
|
wl_global_get_name(const struct wl_global *global,
|
|
|
|
|
const struct wl_client *client)
|
|
|
|
|
{
|
|
|
|
|
return wl_global_is_visible(client, global) ? global->name : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 19:01:26 +02:00
|
|
|
/** Get the version of the given global.
|
|
|
|
|
*
|
|
|
|
|
* \param global The global object.
|
|
|
|
|
* \return The version advertised by the global.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_global
|
|
|
|
|
* \since 1.21
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT uint32_t
|
|
|
|
|
wl_global_get_version(const struct wl_global *global)
|
|
|
|
|
{
|
|
|
|
|
return global->version;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-24 16:02:54 +02:00
|
|
|
/** Get the display object for the given global
|
|
|
|
|
*
|
|
|
|
|
* \param global The global object
|
|
|
|
|
* \return The display object the global is associated with.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_global
|
|
|
|
|
* \since 1.20
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT struct wl_display *
|
|
|
|
|
wl_global_get_display(const struct wl_global *global)
|
|
|
|
|
{
|
|
|
|
|
return global->display;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 16:23:40 +02:00
|
|
|
WL_EXPORT void *
|
|
|
|
|
wl_global_get_user_data(const struct wl_global *global)
|
|
|
|
|
{
|
|
|
|
|
return global->data;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-22 19:41:22 +03:00
|
|
|
/** Set the global's user data
|
|
|
|
|
*
|
|
|
|
|
* \param global The global object
|
|
|
|
|
* \param data The user data pointer
|
|
|
|
|
*
|
|
|
|
|
* \since 1.17.90
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_global_set_user_data(struct wl_global *global, void *data)
|
|
|
|
|
{
|
|
|
|
|
global->data = data;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-13 21:11:17 -08:00
|
|
|
/** Get the current serial number
|
|
|
|
|
*
|
|
|
|
|
* \param display The display object
|
|
|
|
|
*
|
|
|
|
|
* This function returns the most recent serial number, but does not
|
|
|
|
|
* increment it.
|
2015-01-26 11:30:57 -08:00
|
|
|
*
|
2013-11-13 21:11:17 -08:00
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
Switch protocol to using serial numbers for ordering events and requests
The wayland protocol, as X, uses timestamps to match up certain
requests with input events. The problem is that sometimes we need to
send out an event that doesn't have a corresponding timestamped input
event. For example, the pointer focus surface goes away and new
surface needs to receive a pointer enter event. These events are
normally timestamped with the evdev event timestamp, but in this case,
we don't have a evdev timestamp. So we have to go to gettimeofday (or
clock_gettime()) and then we don't know if it's coming from the same
time source etc.
However for all these cases we don't need a real time timestamp, we
just need a serial number that encodes the order of events inside the
server. So we introduce a serial number mechanism that we can use to
order events. We still need real-time timestamps for actual input
device events (motion, buttons, keys, touch), to be able to reason
about double-click speed and movement speed so events that correspond to user input carry both a serial number and a timestamp.
The serial number also give us a mechanism to key together events that
are "logically the same" such as a unicode event and a keycode event,
or a motion event and a relative event from a raw device.
2012-04-11 22:25:51 -04:00
|
|
|
WL_EXPORT uint32_t
|
2023-07-06 18:18:37 +02:00
|
|
|
wl_display_get_serial(const struct wl_display *display)
|
Switch protocol to using serial numbers for ordering events and requests
The wayland protocol, as X, uses timestamps to match up certain
requests with input events. The problem is that sometimes we need to
send out an event that doesn't have a corresponding timestamped input
event. For example, the pointer focus surface goes away and new
surface needs to receive a pointer enter event. These events are
normally timestamped with the evdev event timestamp, but in this case,
we don't have a evdev timestamp. So we have to go to gettimeofday (or
clock_gettime()) and then we don't know if it's coming from the same
time source etc.
However for all these cases we don't need a real time timestamp, we
just need a serial number that encodes the order of events inside the
server. So we introduce a serial number mechanism that we can use to
order events. We still need real-time timestamps for actual input
device events (motion, buttons, keys, touch), to be able to reason
about double-click speed and movement speed so events that correspond to user input carry both a serial number and a timestamp.
The serial number also give us a mechanism to key together events that
are "logically the same" such as a unicode event and a keycode event,
or a motion event and a relative event from a raw device.
2012-04-11 22:25:51 -04:00
|
|
|
{
|
|
|
|
|
return display->serial;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-13 21:11:17 -08:00
|
|
|
/** Get the next serial number
|
|
|
|
|
*
|
|
|
|
|
* \param display The display object
|
|
|
|
|
*
|
|
|
|
|
* This function increments the display serial number and returns the
|
|
|
|
|
* new value.
|
2015-01-26 11:30:57 -08:00
|
|
|
*
|
2013-11-13 21:11:17 -08:00
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
Switch protocol to using serial numbers for ordering events and requests
The wayland protocol, as X, uses timestamps to match up certain
requests with input events. The problem is that sometimes we need to
send out an event that doesn't have a corresponding timestamped input
event. For example, the pointer focus surface goes away and new
surface needs to receive a pointer enter event. These events are
normally timestamped with the evdev event timestamp, but in this case,
we don't have a evdev timestamp. So we have to go to gettimeofday (or
clock_gettime()) and then we don't know if it's coming from the same
time source etc.
However for all these cases we don't need a real time timestamp, we
just need a serial number that encodes the order of events inside the
server. So we introduce a serial number mechanism that we can use to
order events. We still need real-time timestamps for actual input
device events (motion, buttons, keys, touch), to be able to reason
about double-click speed and movement speed so events that correspond to user input carry both a serial number and a timestamp.
The serial number also give us a mechanism to key together events that
are "logically the same" such as a unicode event and a keycode event,
or a motion event and a relative event from a raw device.
2012-04-11 22:25:51 -04:00
|
|
|
WL_EXPORT uint32_t
|
|
|
|
|
wl_display_next_serial(struct wl_display *display)
|
|
|
|
|
{
|
|
|
|
|
display->serial++;
|
|
|
|
|
|
|
|
|
|
return display->serial;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-08 15:39:41 -05:00
|
|
|
WL_EXPORT struct wl_event_loop *
|
2008-10-11 19:21:35 -04:00
|
|
|
wl_display_get_event_loop(struct wl_display *display)
|
|
|
|
|
{
|
|
|
|
|
return display->loop;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-01 15:36:20 -05:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_display_terminate(struct wl_display *display)
|
|
|
|
|
{
|
2021-08-31 18:59:33 +09:00
|
|
|
int ret;
|
|
|
|
|
uint64_t terminate = 1;
|
|
|
|
|
|
2023-05-22 20:10:40 +02:00
|
|
|
display->run = false;
|
2021-08-31 18:59:33 +09:00
|
|
|
|
|
|
|
|
ret = write(display->terminate_efd, &terminate, sizeof(terminate));
|
2024-07-16 06:31:13 -05:00
|
|
|
if (ret < 0 && errno != EAGAIN)
|
|
|
|
|
wl_abort("Write failed at shutdown\n");
|
2010-12-01 15:36:20 -05:00
|
|
|
}
|
|
|
|
|
|
2008-12-05 11:13:50 -05:00
|
|
|
WL_EXPORT void
|
2008-09-30 09:46:10 -04:00
|
|
|
wl_display_run(struct wl_display *display)
|
|
|
|
|
{
|
2023-05-22 20:10:40 +02:00
|
|
|
display->run = true;
|
2010-12-01 15:36:20 -05:00
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
while (display->run) {
|
|
|
|
|
wl_display_flush_clients(display);
|
2023-04-18 17:44:47 +02:00
|
|
|
if (wl_event_loop_dispatch(display->loop, -1) < 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-10-04 16:54:22 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_display_flush_clients(struct wl_display *display)
|
|
|
|
|
{
|
|
|
|
|
struct wl_client *client, *next;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
wl_list_for_each_safe(client, next, &display->client_list, link) {
|
|
|
|
|
ret = wl_connection_flush(client->connection);
|
|
|
|
|
if (ret < 0 && errno == EAGAIN) {
|
|
|
|
|
wl_event_source_fd_update(client->source,
|
|
|
|
|
WL_EVENT_WRITABLE |
|
|
|
|
|
WL_EVENT_READABLE);
|
|
|
|
|
} else if (ret < 0) {
|
|
|
|
|
wl_client_destroy(client);
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-09-30 09:46:10 -04:00
|
|
|
}
|
|
|
|
|
|
2017-12-13 11:51:19 +01:00
|
|
|
/** Destroy all clients connected to the display
|
|
|
|
|
*
|
|
|
|
|
* \param display The display object
|
|
|
|
|
*
|
|
|
|
|
* This function should be called right before wl_display_destroy() to ensure
|
|
|
|
|
* all client resources are closed properly. Destroying a client from within
|
|
|
|
|
* wl_display_destroy_clients() is safe, but creating one will leak resources
|
|
|
|
|
* and raise a warning.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_display_destroy_clients(struct wl_display *display)
|
|
|
|
|
{
|
|
|
|
|
struct wl_list tmp_client_list, *pos;
|
|
|
|
|
struct wl_client *client;
|
|
|
|
|
|
|
|
|
|
/* Move the whole client list to a temporary head because some new clients
|
|
|
|
|
* might be added to the original head. */
|
|
|
|
|
wl_list_init(&tmp_client_list);
|
|
|
|
|
wl_list_insert_list(&tmp_client_list, &display->client_list);
|
|
|
|
|
wl_list_init(&display->client_list);
|
|
|
|
|
|
|
|
|
|
/* wl_list_for_each_safe isn't enough here: it fails if the next client is
|
|
|
|
|
* destroyed by the destroy handler of the current one. */
|
|
|
|
|
while (!wl_list_empty(&tmp_client_list)) {
|
|
|
|
|
pos = tmp_client_list.next;
|
|
|
|
|
client = wl_container_of(pos, client, link);
|
|
|
|
|
|
|
|
|
|
wl_client_destroy(client);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!wl_list_empty(&display->client_list)) {
|
|
|
|
|
wl_log("wl_display_destroy_clients: cannot destroy all clients because "
|
|
|
|
|
"new ones were created by destroy callbacks\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
2021-09-25 22:34:44 -04:00
|
|
|
/** 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;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-22 12:06:34 -04:00
|
|
|
static int
|
2008-09-30 09:46:10 -04:00
|
|
|
socket_data(int fd, uint32_t mask, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wl_display *display = data;
|
|
|
|
|
struct sockaddr_un name;
|
|
|
|
|
socklen_t length;
|
|
|
|
|
int client_fd;
|
|
|
|
|
|
|
|
|
|
length = sizeof name;
|
2012-03-22 14:16:10 +02:00
|
|
|
client_fd = wl_os_accept_cloexec(fd, (struct sockaddr *) &name,
|
|
|
|
|
&length);
|
2008-09-30 09:46:10 -04:00
|
|
|
if (client_fd < 0)
|
2019-04-26 22:40:18 +02:00
|
|
|
wl_log("failed to accept: %s\n", strerror(errno));
|
2012-03-22 14:24:18 +02:00
|
|
|
else
|
2012-10-16 20:32:19 +02:00
|
|
|
if (!wl_client_create(display, client_fd))
|
|
|
|
|
close(client_fd);
|
2011-04-22 12:06:34 -04:00
|
|
|
|
|
|
|
|
return 1;
|
2008-09-30 09:46:10 -04:00
|
|
|
}
|
|
|
|
|
|
2011-04-13 09:38:29 +02:00
|
|
|
static int
|
2014-05-08 10:57:16 -04:00
|
|
|
wl_socket_lock(struct wl_socket *socket)
|
2011-04-13 09:38:29 +02:00
|
|
|
{
|
|
|
|
|
struct stat socket_stat;
|
|
|
|
|
|
2012-06-15 21:09:00 +00:00
|
|
|
snprintf(socket->lock_addr, sizeof socket->lock_addr,
|
|
|
|
|
"%s%s", socket->addr.sun_path, LOCK_SUFFIX);
|
2011-04-13 09:38:29 +02:00
|
|
|
|
2019-10-24 22:31:56 +00:00
|
|
|
socket->fd_lock = open(socket->lock_addr, O_CREAT | O_CLOEXEC | O_RDWR,
|
2014-05-08 10:57:16 -04:00
|
|
|
(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
|
2011-04-13 09:38:29 +02:00
|
|
|
|
2014-05-08 10:57:16 -04:00
|
|
|
if (socket->fd_lock < 0) {
|
2012-05-29 17:38:51 +02:00
|
|
|
wl_log("unable to open lockfile %s check permissions\n",
|
2011-04-13 09:38:29 +02:00
|
|
|
socket->lock_addr);
|
2014-08-06 11:21:59 +02:00
|
|
|
goto err;
|
2011-04-13 09:38:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-05-08 10:57:16 -04:00
|
|
|
if (flock(socket->fd_lock, LOCK_EX | LOCK_NB) < 0) {
|
2012-05-29 17:38:51 +02:00
|
|
|
wl_log("unable to lock lockfile %s, maybe another compositor is running\n",
|
2011-04-13 09:38:29 +02:00
|
|
|
socket->lock_addr);
|
2014-08-06 11:21:59 +02:00
|
|
|
goto err_fd;
|
2011-04-13 09:38:29 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-26 17:08:22 +08:00
|
|
|
if (lstat(socket->addr.sun_path, &socket_stat) < 0 ) {
|
2011-04-13 09:38:29 +02:00
|
|
|
if (errno != ENOENT) {
|
2012-05-29 17:38:51 +02:00
|
|
|
wl_log("did not manage to stat file %s\n",
|
2011-04-13 09:38:29 +02:00
|
|
|
socket->addr.sun_path);
|
2014-08-06 11:21:59 +02:00
|
|
|
goto err_fd;
|
2011-04-13 09:38:29 +02:00
|
|
|
}
|
|
|
|
|
} else if (socket_stat.st_mode & S_IWUSR ||
|
|
|
|
|
socket_stat.st_mode & S_IWGRP) {
|
|
|
|
|
unlink(socket->addr.sun_path);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-08 10:57:16 -04:00
|
|
|
return 0;
|
2014-08-06 11:21:59 +02:00
|
|
|
err_fd:
|
|
|
|
|
close(socket->fd_lock);
|
|
|
|
|
socket->fd_lock = -1;
|
|
|
|
|
err:
|
|
|
|
|
*socket->lock_addr = 0;
|
|
|
|
|
/* we did not set this value here, but without lock the
|
|
|
|
|
* socket won't be created anyway. This prevents the
|
|
|
|
|
* wl_socket_destroy from unlinking already existing socket
|
|
|
|
|
* created by other compositor */
|
|
|
|
|
*socket->addr.sun_path = 0;
|
|
|
|
|
|
|
|
|
|
return -1;
|
2011-04-13 09:38:29 +02:00
|
|
|
}
|
|
|
|
|
|
2014-05-08 10:25:13 -04:00
|
|
|
static int
|
|
|
|
|
wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
|
2008-09-30 09:46:10 -04:00
|
|
|
{
|
2012-06-15 21:32:19 +00:00
|
|
|
int name_size;
|
2019-11-14 14:13:17 +01:00
|
|
|
const char *runtime_dir = "";
|
|
|
|
|
const char *separator = "";
|
|
|
|
|
|
|
|
|
|
if (name[0] != '/') {
|
|
|
|
|
runtime_dir = getenv("XDG_RUNTIME_DIR");
|
2022-03-11 14:08:49 +01:00
|
|
|
if (!runtime_dir || runtime_dir[0] != '/') {
|
|
|
|
|
wl_log("error: XDG_RUNTIME_DIR is invalid or not set in"
|
|
|
|
|
" the environment\n");
|
2019-11-14 14:13:17 +01:00
|
|
|
|
|
|
|
|
/* to prevent programs reporting
|
|
|
|
|
* "failed to add socket: Success" */
|
|
|
|
|
errno = ENOENT;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
separator = "/";
|
2012-06-06 14:30:19 +03:00
|
|
|
}
|
|
|
|
|
|
2010-12-01 15:36:20 -05:00
|
|
|
s->addr.sun_family = AF_LOCAL;
|
|
|
|
|
name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path,
|
2019-11-14 14:13:17 +01:00
|
|
|
"%s%s%s", runtime_dir, separator, name) + 1;
|
2012-06-15 21:32:19 +00:00
|
|
|
|
2024-06-30 22:36:11 +05:30
|
|
|
if (!(name_size > 0))
|
|
|
|
|
wl_abort("Error assigning path name for socket address\n");
|
2012-06-15 21:32:19 +00:00
|
|
|
if (name_size > (int)sizeof s->addr.sun_path) {
|
2019-11-14 14:13:17 +01:00
|
|
|
wl_log("error: socket path \"%s%s%s\" plus null terminator"
|
|
|
|
|
" exceeds 108 bytes\n", runtime_dir, separator, name);
|
2014-08-06 11:21:59 +02:00
|
|
|
*s->addr.sun_path = 0;
|
2012-06-15 21:32:19 +00:00
|
|
|
/* to prevent programs reporting
|
|
|
|
|
* "failed to add socket: Success" */
|
|
|
|
|
errno = ENAMETOOLONG;
|
|
|
|
|
return -1;
|
2014-11-12 03:19:03 +01:00
|
|
|
}
|
2012-06-15 21:32:19 +00:00
|
|
|
|
server: Fix undefined behavior in wl_socket_init_for_display_name
This function constructs a socket path in sun_path using snprintf, which
returns the amount of space that would have been used if the buffer was
large enough. It then checks if this is larger then the actual buffer size
and, if so, returns ENAMETOOLONG. This is correct.
However, after calling snprintf and before checking that the length isn't too
long, it tries to compute a pointer to the part of the path that matches the
input name. It does this by adding the computed path length to the pointer to
the start of the path buffer, which will take it to one-past the null
terminator, and then walking backwards. If the path fits in the buffer, this
will take it at most one-past-the-end of the allocation, which is allowed, but
if the path is longer then the buffer then the pointer addition is undefined behavior.
Fix this by moving the display name computation past the check that the path
length is not too long.
This is detected by the test socket_path_overflow_server_create under ubsan.
Signed-off-by: Fergus Dall <sidereal@google.com>
2021-07-09 18:04:27 +10:00
|
|
|
s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name);
|
|
|
|
|
|
2014-05-08 10:25:13 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-08 11:01:24 -04:00
|
|
|
static int
|
|
|
|
|
_wl_display_add_socket(struct wl_display *display, struct wl_socket *s)
|
|
|
|
|
{
|
|
|
|
|
socklen_t size;
|
|
|
|
|
|
|
|
|
|
s->fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
|
|
|
|
|
if (s->fd < 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = offsetof (struct sockaddr_un, sun_path) + strlen(s->addr.sun_path);
|
|
|
|
|
if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) {
|
2019-04-26 22:40:18 +02:00
|
|
|
wl_log("bind() failed with error: %s\n", strerror(errno));
|
2014-05-08 11:01:24 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-24 16:10:49 +02:00
|
|
|
if (listen(s->fd, 128) < 0) {
|
2019-04-26 22:40:18 +02:00
|
|
|
wl_log("listen() failed with error: %s\n", strerror(errno));
|
2014-05-08 11:01:24 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s->source = wl_event_loop_add_fd(display->loop, s->fd,
|
|
|
|
|
WL_EVENT_READABLE,
|
|
|
|
|
socket_data, display);
|
|
|
|
|
if (s->source == NULL) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_list_insert(display->socket_list.prev, &s->link);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-02 23:24:16 -05:00
|
|
|
|
|
|
|
|
/** 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
|
|
|
|
|
*/
|
2014-05-08 11:01:24 -04:00
|
|
|
WL_EXPORT const char *
|
|
|
|
|
wl_display_add_socket_auto(struct wl_display *display)
|
|
|
|
|
{
|
|
|
|
|
struct wl_socket *s;
|
|
|
|
|
int displayno = 0;
|
server: Extend display name string size
Typically this is a number between 0 and 32. Just that the compiler doesn't
know that well. Make the string buffer a bit larger, so that it fits the
longer integers. Fixes build warnings like:
../subprojects/wayland/src/wayland-server.c: In function ‘wl_display_add_socket_auto’:
../subprojects/wayland/src/wayland-server.c:1649:70: error: ‘%d’ directive output may be truncated writing between 1 and 11 bytes into a region of size 8 [-Werror=format-truncation=]
1649 | snprintf(display_name, sizeof display_name, "wayland-%d", displayno);
| ^~
../subprojects/wayland/src/wayland-server.c:1649:61: note: directive argument in the range [-2147483647, 32]
1649 | snprintf(display_name, sizeof display_name, "wayland-%d", displayno);
| ^~~~~~~~~~~~
../subprojects/wayland/src/wayland-server.c:1649:17: note: ‘snprintf’ output between 10 and 20 bytes into a destination of size 16
1649 | snprintf(display_name, sizeof display_name, "wayland-%d", displayno);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
Seen in GTK CI.
Signed-off-by: Carlos Garnacho <carlosg@gnome.org>
2022-08-05 00:35:40 +02:00
|
|
|
char display_name[20] = "";
|
2014-05-08 11:01:24 -04:00
|
|
|
|
|
|
|
|
/* A reasonable number of maximum default sockets. If
|
|
|
|
|
* you need more than this, use the explicit add_socket API. */
|
|
|
|
|
const int MAX_DISPLAYNO = 32;
|
|
|
|
|
|
2014-08-07 16:46:52 +03:00
|
|
|
s = wl_socket_alloc();
|
2014-05-08 11:01:24 -04:00
|
|
|
if (s == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
snprintf(display_name, sizeof display_name, "wayland-%d", displayno);
|
|
|
|
|
if (wl_socket_init_for_display_name(s, display_name) < 0) {
|
|
|
|
|
wl_socket_destroy(s);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wl_socket_lock(s) < 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (_wl_display_add_socket(display, s) < 0) {
|
|
|
|
|
wl_socket_destroy(s);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s->display_name;
|
|
|
|
|
} while (displayno++ < MAX_DISPLAYNO);
|
|
|
|
|
|
|
|
|
|
/* Ran out of display names. */
|
|
|
|
|
wl_socket_destroy(s);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-17 16:49:59 -08:00
|
|
|
/** Add a socket with an existing fd to Wayland display for the clients to connect.
|
|
|
|
|
*
|
|
|
|
|
* \param display Wayland display to which the socket should be added.
|
|
|
|
|
* \param sock_fd The existing socket file descriptor to be used
|
|
|
|
|
* \return 0 if success. -1 if failed.
|
|
|
|
|
*
|
|
|
|
|
* The existing socket fd must already be created, opened, and locked.
|
|
|
|
|
* The fd must be properly set to CLOEXEC and bound to a socket file
|
|
|
|
|
* with both bind() and listen() already called.
|
|
|
|
|
*
|
2023-06-05 11:59:31 +02:00
|
|
|
* On success, the socket fd ownership is transferred to libwayland:
|
|
|
|
|
* libwayland will close the socket when the display is destroyed.
|
|
|
|
|
*
|
2015-12-17 16:49:59 -08:00
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT int
|
|
|
|
|
wl_display_add_socket_fd(struct wl_display *display, int sock_fd)
|
|
|
|
|
{
|
|
|
|
|
struct wl_socket *s;
|
|
|
|
|
struct stat buf;
|
|
|
|
|
|
|
|
|
|
/* Require a valid fd or fail */
|
|
|
|
|
if (sock_fd < 0 || fstat(sock_fd, &buf) < 0 || !S_ISSOCK(buf.st_mode)) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s = wl_socket_alloc();
|
|
|
|
|
if (s == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2016-02-01 19:35:51 +01:00
|
|
|
s->source = wl_event_loop_add_fd(display->loop, sock_fd,
|
2015-12-17 16:49:59 -08:00
|
|
|
WL_EVENT_READABLE,
|
|
|
|
|
socket_data, display);
|
|
|
|
|
if (s->source == NULL) {
|
|
|
|
|
wl_log("failed to establish event source\n");
|
2016-02-01 19:35:51 +01:00
|
|
|
wl_socket_destroy(s);
|
2015-12-17 16:49:59 -08:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-01 19:35:51 +01:00
|
|
|
/* Reuse the existing fd */
|
|
|
|
|
s->fd = sock_fd;
|
|
|
|
|
|
2015-12-17 16:49:59 -08:00
|
|
|
wl_list_insert(display->socket_list.prev, &s->link);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-15 14:51:27 +05:30
|
|
|
/** Add a socket to Wayland display for the clients to connect.
|
|
|
|
|
*
|
|
|
|
|
* \param display Wayland display to which the socket should be added.
|
|
|
|
|
* \param name Name of the Unix socket.
|
|
|
|
|
* \return 0 if success. -1 if failed.
|
|
|
|
|
*
|
|
|
|
|
* This adds a Unix socket to Wayland display which can be used by clients to
|
|
|
|
|
* connect to Wayland display.
|
|
|
|
|
*
|
|
|
|
|
* If NULL is passed as name, then it would look for WAYLAND_DISPLAY env
|
|
|
|
|
* variable for the socket name. If WAYLAND_DISPLAY is not set, then default
|
|
|
|
|
* wayland-0 is used.
|
|
|
|
|
*
|
2019-11-14 14:13:17 +01:00
|
|
|
* If the socket name is a relative path, the Unix socket will be created in
|
|
|
|
|
* the directory pointed to by environment variable XDG_RUNTIME_DIR. If
|
2022-03-11 14:08:49 +01:00
|
|
|
* XDG_RUNTIME_DIR is invalid or not set, then this function fails and returns -1.
|
2019-11-14 14:13:17 +01:00
|
|
|
*
|
|
|
|
|
* If the socket name is an absolute path, then it is used as-is for the
|
|
|
|
|
* the Unix socket.
|
2014-10-15 14:51:27 +05:30
|
|
|
*
|
2019-11-14 14:13:17 +01:00
|
|
|
* The length of the computed socket path must not exceed the maximum length
|
|
|
|
|
* of a Unix socket path.
|
|
|
|
|
* The function also fails if the user does not have write permission in the
|
|
|
|
|
* directory or if the path is already in use.
|
2014-10-15 14:51:27 +05:30
|
|
|
*
|
|
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
2014-05-08 10:25:13 -04:00
|
|
|
WL_EXPORT int
|
|
|
|
|
wl_display_add_socket(struct wl_display *display, const char *name)
|
|
|
|
|
{
|
|
|
|
|
struct wl_socket *s;
|
|
|
|
|
|
2014-08-07 16:46:52 +03:00
|
|
|
s = wl_socket_alloc();
|
2014-05-08 10:25:13 -04:00
|
|
|
if (s == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (name == NULL)
|
|
|
|
|
name = getenv("WAYLAND_DISPLAY");
|
|
|
|
|
if (name == NULL)
|
|
|
|
|
name = "wayland-0";
|
|
|
|
|
|
|
|
|
|
if (wl_socket_init_for_display_name(s, name) < 0) {
|
|
|
|
|
wl_socket_destroy(s);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-08 10:57:16 -04:00
|
|
|
if (wl_socket_lock(s) < 0) {
|
2014-05-08 10:22:25 -04:00
|
|
|
wl_socket_destroy(s);
|
2011-04-13 09:38:29 +02:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-08 11:01:24 -04:00
|
|
|
if (_wl_display_add_socket(display, s) < 0) {
|
2014-05-08 10:24:06 -04:00
|
|
|
wl_socket_destroy(s);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-30 09:46:10 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
2010-12-08 15:12:58 -05:00
|
|
|
|
2013-01-11 14:29:32 -06:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_display_add_destroy_listener(struct wl_display *display,
|
|
|
|
|
struct wl_listener *listener)
|
|
|
|
|
{
|
2017-01-24 16:34:28 +02:00
|
|
|
wl_priv_signal_add(&display->destroy_signal, listener);
|
2013-01-11 14:29:32 -06:00
|
|
|
}
|
|
|
|
|
|
2016-08-09 12:46:51 +02:00
|
|
|
/** Registers a listener for the client connection signal.
|
|
|
|
|
* When a new client object is created, \a listener will be notified, carrying
|
|
|
|
|
* a pointer to the new wl_client object.
|
|
|
|
|
*
|
|
|
|
|
* \ref wl_client_create
|
|
|
|
|
* \ref wl_display
|
|
|
|
|
* \ref wl_listener
|
|
|
|
|
*
|
|
|
|
|
* \param display The display object
|
|
|
|
|
* \param listener Signal handler object
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_display_add_client_created_listener(struct wl_display *display,
|
|
|
|
|
struct wl_listener *listener)
|
|
|
|
|
{
|
2017-01-24 16:34:28 +02:00
|
|
|
wl_priv_signal_add(&display->create_client_signal, listener);
|
2016-08-09 12:46:51 +02:00
|
|
|
}
|
|
|
|
|
|
2013-01-11 14:29:32 -06:00
|
|
|
WL_EXPORT struct wl_listener *
|
|
|
|
|
wl_display_get_destroy_listener(struct wl_display *display,
|
|
|
|
|
wl_notify_func_t notify)
|
|
|
|
|
{
|
2017-01-24 16:34:28 +02:00
|
|
|
return wl_priv_signal_get(&display->destroy_signal, notify);
|
2013-01-11 14:29:32 -06:00
|
|
|
}
|
|
|
|
|
|
2013-06-27 20:09:20 -05:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_resource_set_implementation(struct wl_resource *resource,
|
|
|
|
|
const void *implementation,
|
|
|
|
|
void *data, wl_resource_destroy_func_t destroy)
|
|
|
|
|
{
|
|
|
|
|
resource->object.implementation = implementation;
|
|
|
|
|
resource->data = data;
|
|
|
|
|
resource->destroy = destroy;
|
2013-07-17 21:58:46 -05:00
|
|
|
resource->dispatcher = NULL;
|
2013-06-27 20:09:20 -05:00
|
|
|
}
|
|
|
|
|
|
2013-07-17 21:58:46 -05:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_resource_set_dispatcher(struct wl_resource *resource,
|
|
|
|
|
wl_dispatcher_func_t dispatcher,
|
|
|
|
|
const void *implementation,
|
|
|
|
|
void *data, wl_resource_destroy_func_t destroy)
|
|
|
|
|
{
|
|
|
|
|
resource->dispatcher = dispatcher;
|
|
|
|
|
resource->object.implementation = implementation;
|
|
|
|
|
resource->data = data;
|
|
|
|
|
resource->destroy = destroy;
|
|
|
|
|
}
|
2013-06-27 20:09:20 -05:00
|
|
|
|
2016-08-11 17:23:09 +02:00
|
|
|
/** Create a new resource object
|
|
|
|
|
*
|
|
|
|
|
* \param client The client owner of the new resource.
|
|
|
|
|
* \param interface The interface of the new resource.
|
|
|
|
|
* \param version The version of the new resource.
|
|
|
|
|
* \param id The id of the new resource. If 0, an available id will be used.
|
|
|
|
|
*
|
|
|
|
|
* Listeners added with \a wl_client_add_resource_created_listener will be
|
|
|
|
|
* notified at the end of this function.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_resource
|
|
|
|
|
*/
|
2013-06-27 20:09:20 -05:00
|
|
|
WL_EXPORT struct wl_resource *
|
|
|
|
|
wl_resource_create(struct wl_client *client,
|
|
|
|
|
const struct wl_interface *interface,
|
|
|
|
|
int version, uint32_t id)
|
2011-08-19 16:57:48 -04:00
|
|
|
{
|
|
|
|
|
struct wl_resource *resource;
|
|
|
|
|
|
2022-01-31 22:23:30 +01:00
|
|
|
resource = zalloc(sizeof *resource);
|
2013-07-02 15:39:03 -04:00
|
|
|
if (resource == NULL)
|
2011-08-19 16:57:48 -04:00
|
|
|
return NULL;
|
|
|
|
|
|
2022-02-09 06:26:18 +06:00
|
|
|
if (id == 0) {
|
2013-06-27 20:09:20 -05:00
|
|
|
id = wl_map_insert_new(&client->objects, 0, NULL);
|
2022-02-09 06:26:18 +06:00
|
|
|
if (id == 0) {
|
|
|
|
|
free(resource);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-06-27 20:09:20 -05:00
|
|
|
|
2013-06-27 20:09:18 -05:00
|
|
|
resource->object.id = id;
|
|
|
|
|
resource->object.interface = interface;
|
2013-06-27 20:09:20 -05:00
|
|
|
resource->object.implementation = NULL;
|
2013-06-27 20:09:18 -05:00
|
|
|
|
2017-01-24 16:34:30 +02:00
|
|
|
wl_signal_init(&resource->deprecated_destroy_signal);
|
|
|
|
|
wl_priv_signal_init(&resource->destroy_signal);
|
2013-06-27 20:09:18 -05:00
|
|
|
|
2013-06-18 12:42:40 -05:00
|
|
|
resource->destroy = NULL;
|
2013-06-27 20:09:18 -05:00
|
|
|
resource->client = client;
|
2013-06-27 20:09:20 -05:00
|
|
|
resource->data = NULL;
|
|
|
|
|
resource->version = version;
|
2013-07-17 21:58:46 -05:00
|
|
|
resource->dispatcher = NULL;
|
2011-08-19 16:57:48 -04:00
|
|
|
|
2015-01-23 16:21:15 +08:00
|
|
|
if (wl_map_insert_at(&client->objects, 0, id, resource) < 0) {
|
2022-02-09 05:36:11 +06:00
|
|
|
if (errno == EINVAL) {
|
|
|
|
|
wl_resource_post_error(client->display_resource,
|
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
|
"invalid new id %d", id);
|
|
|
|
|
}
|
2011-08-19 22:50:53 -04:00
|
|
|
free(resource);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-08-19 16:57:48 -04:00
|
|
|
|
2017-01-24 16:34:29 +02:00
|
|
|
wl_priv_signal_emit(&client->resource_created_signal, resource);
|
2011-08-19 16:57:48 -04:00
|
|
|
return resource;
|
|
|
|
|
}
|
2011-11-15 08:58:34 -05:00
|
|
|
|
2013-07-02 14:34:42 -04:00
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_log_set_handler_server(wl_log_func_t handler)
|
|
|
|
|
{
|
|
|
|
|
wl_log_handler = handler;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 09:33:06 +02:00
|
|
|
/** Adds a new protocol logger.
|
|
|
|
|
*
|
|
|
|
|
* When a new protocol message arrives or is sent from the server
|
|
|
|
|
* all the protocol logger functions will be called, carrying the
|
|
|
|
|
* \a user_data pointer, the type of the message (request or
|
|
|
|
|
* event) and the actual message.
|
|
|
|
|
* The lifetime of the messages passed to the logger function ends
|
|
|
|
|
* when they return so the messages cannot be stored and accessed
|
|
|
|
|
* later.
|
|
|
|
|
*
|
|
|
|
|
* \a errno is set on error.
|
|
|
|
|
*
|
2016-08-17 16:08:17 -07:00
|
|
|
* \param display The display object
|
2016-08-12 09:33:06 +02:00
|
|
|
* \param func The function to call to log a new protocol message
|
|
|
|
|
* \param user_data The user data pointer to pass to \a func
|
|
|
|
|
*
|
2024-09-12 15:26:26 +02:00
|
|
|
* \return The protocol logger object on success, NULL on failure.
|
2016-08-12 09:33:06 +02:00
|
|
|
*
|
|
|
|
|
* \sa wl_protocol_logger_destroy
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT struct wl_protocol_logger *
|
|
|
|
|
wl_display_add_protocol_logger(struct wl_display *display,
|
|
|
|
|
wl_protocol_logger_func_t func, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
struct wl_protocol_logger *logger;
|
|
|
|
|
|
2022-01-31 22:23:30 +01:00
|
|
|
logger = zalloc(sizeof *logger);
|
2016-08-12 09:33:06 +02:00
|
|
|
if (!logger)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
logger->func = func;
|
|
|
|
|
logger->user_data = user_data;
|
|
|
|
|
wl_list_insert(&display->protocol_loggers, &logger->link);
|
|
|
|
|
|
|
|
|
|
return logger;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Destroys a protocol logger.
|
|
|
|
|
*
|
|
|
|
|
* This function destroys a protocol logger and removes it from the display
|
|
|
|
|
* it was added to with \a wl_display_add_protocol_logger.
|
|
|
|
|
* The \a logger object becomes invalid after calling this function.
|
|
|
|
|
*
|
|
|
|
|
* \sa wl_display_add_protocol_logger
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_protocol_logger
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_protocol_logger_destroy(struct wl_protocol_logger *logger)
|
|
|
|
|
{
|
|
|
|
|
wl_list_remove(&logger->link);
|
|
|
|
|
free(logger);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-24 09:24:23 -06:00
|
|
|
/** Add support for a wl_shm pixel format
|
|
|
|
|
*
|
|
|
|
|
* \param display The display object
|
|
|
|
|
* \param format The wl_shm pixel format to advertise
|
|
|
|
|
* \return A pointer to the wl_shm format that was added to the list
|
|
|
|
|
* or NULL if adding it to the list failed.
|
|
|
|
|
*
|
|
|
|
|
* Add the specified wl_shm format to the list of formats the wl_shm
|
|
|
|
|
* object advertises when a client binds to it. Adding a format to
|
|
|
|
|
* the list means that clients will know that the compositor supports
|
|
|
|
|
* this format and may use it for creating wl_shm buffers. The
|
|
|
|
|
* compositor must be able to handle the pixel format when a client
|
|
|
|
|
* requests it.
|
|
|
|
|
*
|
|
|
|
|
* The compositor by default supports WL_SHM_FORMAT_ARGB8888 and
|
|
|
|
|
* WL_SHM_FORMAT_XRGB8888.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT uint32_t *
|
|
|
|
|
wl_display_add_shm_format(struct wl_display *display, uint32_t format)
|
|
|
|
|
{
|
|
|
|
|
uint32_t *p = NULL;
|
|
|
|
|
|
|
|
|
|
p = wl_array_add(&display->additional_shm_formats, sizeof *p);
|
|
|
|
|
|
|
|
|
|
if (p != NULL)
|
|
|
|
|
*p = format;
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get list of additional wl_shm pixel formats
|
|
|
|
|
*
|
|
|
|
|
* \param display The display object
|
|
|
|
|
*
|
|
|
|
|
* This function returns the list of addition wl_shm pixel formats
|
|
|
|
|
* that the compositor supports. WL_SHM_FORMAT_ARGB8888 and
|
|
|
|
|
* WL_SHM_FORMAT_XRGB8888 are always supported and not included in the
|
|
|
|
|
* array, but all formats added through wl_display_add_shm_format()
|
|
|
|
|
* will be in the array.
|
2015-01-26 11:30:57 -08:00
|
|
|
*
|
2015-01-24 09:24:23 -06:00
|
|
|
* \sa wl_display_add_shm_format()
|
2015-01-26 11:30:57 -08:00
|
|
|
*
|
2016-05-12 15:52:37 -05:00
|
|
|
* \private
|
|
|
|
|
*
|
2015-01-24 09:24:23 -06:00
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
|
|
|
|
struct wl_array *
|
|
|
|
|
wl_display_get_additional_shm_formats(struct wl_display *display)
|
|
|
|
|
{
|
|
|
|
|
return &display->additional_shm_formats;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-09 12:46:53 +02:00
|
|
|
/** Get the list of currently connected clients
|
|
|
|
|
*
|
|
|
|
|
* \param display The display object
|
|
|
|
|
*
|
|
|
|
|
* This function returns a pointer to the list of clients currently
|
|
|
|
|
* connected to the display. You can iterate on the list by using
|
|
|
|
|
* the \a wl_client_for_each macro.
|
|
|
|
|
* The returned value is valid for the lifetime of the \a display.
|
|
|
|
|
* You must not modify the returned list, but only access it.
|
|
|
|
|
*
|
|
|
|
|
* \sa wl_client_for_each()
|
|
|
|
|
* \sa wl_client_get_link()
|
|
|
|
|
* \sa wl_client_from_link()
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_display
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT struct wl_list *
|
|
|
|
|
wl_display_get_client_list(struct wl_display *display)
|
|
|
|
|
{
|
|
|
|
|
return &display->client_list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Get the link by which a client is inserted in the client list
|
|
|
|
|
*
|
|
|
|
|
* \param client The client object
|
|
|
|
|
*
|
|
|
|
|
* \sa wl_client_for_each()
|
|
|
|
|
* \sa wl_display_get_client_list()
|
|
|
|
|
* \sa wl_client_from_link()
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT struct wl_list *
|
|
|
|
|
wl_client_get_link(struct wl_client *client)
|
|
|
|
|
{
|
|
|
|
|
return &client->link;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Get a wl_client by its link
|
|
|
|
|
*
|
|
|
|
|
* \param link The link of a wl_client
|
|
|
|
|
*
|
|
|
|
|
* \sa wl_client_for_each()
|
|
|
|
|
* \sa wl_display_get_client_list()
|
|
|
|
|
* \sa wl_client_get_link()
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT struct wl_client *
|
|
|
|
|
wl_client_from_link(struct wl_list *link)
|
|
|
|
|
{
|
2019-06-01 15:11:48 -07:00
|
|
|
struct wl_client *client;
|
|
|
|
|
|
|
|
|
|
return wl_container_of(link, client, link);
|
2016-08-09 12:46:53 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-11 17:23:09 +02:00
|
|
|
/** Add a listener for the client's resource creation signal
|
|
|
|
|
*
|
|
|
|
|
* \param client The client object
|
|
|
|
|
* \param listener The listener to be added
|
|
|
|
|
*
|
|
|
|
|
* When a new resource is created for this client the listener
|
|
|
|
|
* will be notified, carrying the new resource as the data argument.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_client_add_resource_created_listener(struct wl_client *client,
|
|
|
|
|
struct wl_listener *listener)
|
|
|
|
|
{
|
2017-01-24 16:34:29 +02:00
|
|
|
wl_priv_signal_add(&client->resource_created_signal, listener);
|
2016-08-11 17:23:09 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-11 17:23:10 +02:00
|
|
|
struct wl_resource_iterator_context {
|
|
|
|
|
void *user_data;
|
|
|
|
|
wl_client_for_each_resource_iterator_func_t it;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static enum wl_iterator_result
|
2017-12-06 11:22:21 -06:00
|
|
|
resource_iterator_helper(void *res, void *user_data, uint32_t flags)
|
2016-08-11 17:23:10 +02:00
|
|
|
{
|
|
|
|
|
struct wl_resource_iterator_context *context = user_data;
|
|
|
|
|
struct wl_resource *resource = res;
|
|
|
|
|
|
|
|
|
|
return context->it(resource, context->user_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Iterate over all the resources of a client
|
|
|
|
|
*
|
|
|
|
|
* \param client The client object
|
|
|
|
|
* \param iterator The iterator function
|
|
|
|
|
* \param user_data The user data pointer
|
|
|
|
|
*
|
|
|
|
|
* The function pointed by \a iterator will be called for each
|
|
|
|
|
* resource owned by the client. The \a user_data will be passed
|
|
|
|
|
* as the second argument of the iterator function.
|
|
|
|
|
* If the \a iterator function returns \a WL_ITERATOR_CONTINUE the iteration
|
|
|
|
|
* will continue, if it returns \a WL_ITERATOR_STOP it will stop.
|
|
|
|
|
*
|
|
|
|
|
* Creating and destroying resources while iterating is safe, but new
|
|
|
|
|
* resources may or may not be picked up by the iterator.
|
|
|
|
|
*
|
|
|
|
|
* \sa wl_iterator_result
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_client
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_client_for_each_resource(struct wl_client *client,
|
|
|
|
|
wl_client_for_each_resource_iterator_func_t iterator,
|
|
|
|
|
void *user_data)
|
|
|
|
|
{
|
|
|
|
|
struct wl_resource_iterator_context context = {
|
|
|
|
|
.user_data = user_data,
|
|
|
|
|
.it = iterator,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
wl_map_for_each(&client->objects, resource_iterator_helper, &context);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-31 23:09:26 +01:00
|
|
|
static void
|
|
|
|
|
handle_noop(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
/* Do nothing */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Emits this signal, notifying all registered listeners.
|
|
|
|
|
*
|
|
|
|
|
* A safer version of wl_signal_emit() which can gracefully handle additions
|
|
|
|
|
* and deletions of any signal listener from within listener notification
|
|
|
|
|
* callbacks.
|
|
|
|
|
*
|
|
|
|
|
* Listeners deleted during a signal emission and which have not already been
|
|
|
|
|
* notified at the time of deletion are not notified by that emission.
|
|
|
|
|
*
|
|
|
|
|
* Listeners added (or readded) during signal emission are ignored by that
|
|
|
|
|
* emission.
|
|
|
|
|
*
|
|
|
|
|
* Note that repurposing a listener without explicitly removing it and readding
|
|
|
|
|
* it is not supported and can lead to unexpected behavior.
|
|
|
|
|
*
|
|
|
|
|
* \param signal The signal object that will emit the signal
|
|
|
|
|
* \param data The data that will be emitted with the signal
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_signal
|
|
|
|
|
* \since 1.20.90
|
|
|
|
|
*/
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_signal_emit_mutable(struct wl_signal *signal, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wl_listener cursor;
|
|
|
|
|
struct wl_listener end;
|
|
|
|
|
|
|
|
|
|
/* Add two special markers: one cursor and one end marker. This way, we
|
|
|
|
|
* know that we've already called listeners on the left of the cursor
|
|
|
|
|
* and that we don't want to call listeners on the right of the end
|
|
|
|
|
* marker. The 'it' function can remove any element it wants from the
|
|
|
|
|
* list without troubles.
|
|
|
|
|
*
|
|
|
|
|
* There was a previous attempt that used to steal the whole list of
|
|
|
|
|
* listeners but then that broke wl_signal_get().
|
|
|
|
|
*
|
|
|
|
|
* wl_list_for_each_safe tries to be safe but it fails: it works fine
|
|
|
|
|
* if the current item is removed, but not if the next one is. */
|
|
|
|
|
wl_list_insert(&signal->listener_list, &cursor.link);
|
|
|
|
|
cursor.notify = handle_noop;
|
|
|
|
|
wl_list_insert(signal->listener_list.prev, &end.link);
|
|
|
|
|
end.notify = handle_noop;
|
|
|
|
|
|
|
|
|
|
while (cursor.link.next != &end.link) {
|
|
|
|
|
struct wl_list *pos = cursor.link.next;
|
|
|
|
|
struct wl_listener *l = wl_container_of(pos, l, link);
|
|
|
|
|
|
|
|
|
|
wl_list_remove(&cursor.link);
|
|
|
|
|
wl_list_insert(pos, &cursor.link);
|
|
|
|
|
|
|
|
|
|
l->notify(l, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_list_remove(&cursor.link);
|
|
|
|
|
wl_list_remove(&end.link);
|
|
|
|
|
}
|
|
|
|
|
|
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
2021-09-25 22:34:44 -04:00
|
|
|
/** 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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-25 14:24:44 +02:00
|
|
|
/** \cond INTERNAL */
|
|
|
|
|
|
2017-01-24 16:34:28 +02:00
|
|
|
/** Initialize a wl_priv_signal object
|
|
|
|
|
*
|
|
|
|
|
* wl_priv_signal is a safer implementation of a signal type, with the same API
|
|
|
|
|
* as wl_signal, but kept as a private utility of libwayland-server.
|
|
|
|
|
* It is safer because listeners can be removed from within wl_priv_signal_emit()
|
|
|
|
|
* without corrupting the signal's list.
|
|
|
|
|
*
|
|
|
|
|
* Before passing a wl_priv_signal object to any other function it must be
|
2020-12-17 15:42:10 -05:00
|
|
|
* initialized by using wl_priv_signal_init().
|
2017-01-24 16:34:28 +02:00
|
|
|
*
|
|
|
|
|
* \memberof wl_priv_signal
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
wl_priv_signal_init(struct wl_priv_signal *signal)
|
|
|
|
|
{
|
|
|
|
|
wl_list_init(&signal->listener_list);
|
|
|
|
|
wl_list_init(&signal->emit_list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Add a listener to a signal
|
|
|
|
|
*
|
|
|
|
|
* The new listener will be called when calling wl_signal_emit(). If a listener is
|
|
|
|
|
* added to the signal while wl_signal_emit() is running it will be called from
|
|
|
|
|
* the next time wl_priv_signal_emit() is called.
|
|
|
|
|
* To remove a listener call wl_list_remove() on its link member.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_priv_signal
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener)
|
|
|
|
|
{
|
|
|
|
|
wl_list_insert(signal->listener_list.prev, &listener->link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Get a listener added to a signal
|
|
|
|
|
*
|
|
|
|
|
* Returns the listener added to the given \a signal and with the given
|
|
|
|
|
* \a notify function, or NULL if there isn't any.
|
2020-12-17 15:42:10 -05:00
|
|
|
* Calling this function from within wl_priv_signal_emit() is safe and will
|
2017-01-24 16:34:28 +02:00
|
|
|
* return the correct value.
|
|
|
|
|
*
|
|
|
|
|
* \memberof wl_priv_signal
|
|
|
|
|
*/
|
|
|
|
|
struct wl_listener *
|
|
|
|
|
wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify)
|
|
|
|
|
{
|
|
|
|
|
struct wl_listener *l;
|
|
|
|
|
|
|
|
|
|
wl_list_for_each(l, &signal->listener_list, link)
|
|
|
|
|
if (l->notify == notify)
|
|
|
|
|
return l;
|
|
|
|
|
wl_list_for_each(l, &signal->emit_list, link)
|
|
|
|
|
if (l->notify == notify)
|
|
|
|
|
return l;
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Emit the signal, calling all the installed listeners
|
|
|
|
|
*
|
|
|
|
|
* Iterate over all the listeners added to this \a signal and call
|
|
|
|
|
* their \a notify function pointer, passing on the given \a data.
|
|
|
|
|
* Removing or adding a listener from within wl_priv_signal_emit()
|
|
|
|
|
* is safe.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
wl_priv_signal_emit(struct wl_priv_signal *signal, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wl_listener *l;
|
|
|
|
|
struct wl_list *pos;
|
|
|
|
|
|
|
|
|
|
wl_list_insert_list(&signal->emit_list, &signal->listener_list);
|
|
|
|
|
wl_list_init(&signal->listener_list);
|
|
|
|
|
|
|
|
|
|
/* Take every element out of the list and put them in a temporary list.
|
|
|
|
|
* This way, the 'it' func can remove any element it wants from the list
|
|
|
|
|
* without troubles, because we always get the first element, not the
|
|
|
|
|
* one after the current, which may be invalid.
|
|
|
|
|
* wl_list_for_each_safe tries to be safe but it fails: it works fine
|
|
|
|
|
* if the current item is removed, but not if the next one is. */
|
|
|
|
|
while (!wl_list_empty(&signal->emit_list)) {
|
|
|
|
|
pos = signal->emit_list.next;
|
|
|
|
|
l = wl_container_of(pos, l, link);
|
|
|
|
|
|
|
|
|
|
wl_list_remove(pos);
|
|
|
|
|
wl_list_insert(&signal->listener_list, pos);
|
|
|
|
|
|
|
|
|
|
l->notify(l, data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-16 15:00:59 -05:00
|
|
|
/** Emit the signal for the last time, calling all the installed listeners
|
|
|
|
|
*
|
|
|
|
|
* Iterate over all the listeners added to this \a signal and call
|
|
|
|
|
* their \a notify function pointer, passing on the given \a data.
|
|
|
|
|
* Removing or adding a listener from within wl_priv_signal_emit()
|
|
|
|
|
* is safe, as is freeing the structure containing the listener.
|
|
|
|
|
*
|
|
|
|
|
* A large body of external code assumes it's ok to free a destruction
|
|
|
|
|
* listener without removing that listener from the list. Mixing code
|
|
|
|
|
* that acts like this and code that doesn't will result in list
|
|
|
|
|
* corruption.
|
|
|
|
|
*
|
|
|
|
|
* We resolve this by removing each item from the list and isolating it
|
|
|
|
|
* in another list. We discard it completely after firing the notifier.
|
|
|
|
|
* This should allow interoperability between code that unlinks its
|
|
|
|
|
* destruction listeners and code that just frees structures they're in.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wl_listener *l;
|
|
|
|
|
struct wl_list *pos;
|
|
|
|
|
|
|
|
|
|
/* During a destructor notifier isolate every list item before
|
|
|
|
|
* notifying. This renders harmless the long standing misuse
|
|
|
|
|
* of freeing listeners without removing them, but allows
|
|
|
|
|
* callers that do choose to remove them to interoperate with
|
|
|
|
|
* ones that don't. */
|
|
|
|
|
while (!wl_list_empty(&signal->listener_list)) {
|
|
|
|
|
pos = signal->listener_list.next;
|
|
|
|
|
l = wl_container_of(pos, l, link);
|
|
|
|
|
|
|
|
|
|
wl_list_remove(pos);
|
|
|
|
|
wl_list_init(pos);
|
|
|
|
|
|
|
|
|
|
l->notify(l, data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-25 14:24:44 +02:00
|
|
|
/** \endcond INTERNAL */
|
|
|
|
|
|
2015-01-02 18:29:16 -08:00
|
|
|
/** \cond */ /* Deprecated functions below. */
|
2013-07-02 14:34:42 -04:00
|
|
|
|
2024-06-29 15:05:00 +03:00
|
|
|
WL_DEPRECATED
|
2013-07-02 14:34:42 -04:00
|
|
|
uint32_t
|
|
|
|
|
wl_client_add_resource(struct wl_client *client,
|
2024-06-29 15:05:00 +03:00
|
|
|
struct wl_resource *resource);
|
2013-07-02 14:34:42 -04:00
|
|
|
|
|
|
|
|
WL_EXPORT uint32_t
|
|
|
|
|
wl_client_add_resource(struct wl_client *client,
|
|
|
|
|
struct wl_resource *resource)
|
|
|
|
|
{
|
|
|
|
|
if (resource->object.id == 0) {
|
|
|
|
|
resource->object.id =
|
|
|
|
|
wl_map_insert_new(&client->objects,
|
|
|
|
|
WL_MAP_ENTRY_LEGACY, resource);
|
2022-02-09 06:26:18 +06:00
|
|
|
if (resource->object.id == 0)
|
|
|
|
|
return 0;
|
2013-07-02 14:34:42 -04:00
|
|
|
} else if (wl_map_insert_at(&client->objects, WL_MAP_ENTRY_LEGACY,
|
|
|
|
|
resource->object.id, resource) < 0) {
|
2022-02-09 05:36:11 +06:00
|
|
|
if (errno == EINVAL) {
|
|
|
|
|
wl_resource_post_error(client->display_resource,
|
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
|
"invalid new id %d",
|
|
|
|
|
resource->object.id);
|
|
|
|
|
}
|
2013-07-02 14:34:42 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resource->client = client;
|
2017-01-24 16:34:30 +02:00
|
|
|
wl_signal_init(&resource->deprecated_destroy_signal);
|
2013-07-02 14:34:42 -04:00
|
|
|
|
|
|
|
|
return resource->object.id;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-29 15:05:00 +03:00
|
|
|
WL_DEPRECATED
|
2013-07-02 14:34:42 -04:00
|
|
|
struct wl_resource *
|
|
|
|
|
wl_client_add_object(struct wl_client *client,
|
|
|
|
|
const struct wl_interface *interface,
|
|
|
|
|
const void *implementation,
|
2024-06-29 15:05:00 +03:00
|
|
|
uint32_t id, void *data);
|
2013-07-02 14:34:42 -04:00
|
|
|
|
2011-11-15 08:58:34 -05:00
|
|
|
WL_EXPORT struct wl_resource *
|
2013-07-02 14:34:42 -04:00
|
|
|
wl_client_add_object(struct wl_client *client,
|
2011-11-15 08:58:34 -05:00
|
|
|
const struct wl_interface *interface,
|
2013-07-02 14:34:42 -04:00
|
|
|
const void *implementation, uint32_t id, void *data)
|
2011-11-15 08:58:34 -05:00
|
|
|
{
|
2013-06-27 20:09:20 -05:00
|
|
|
struct wl_resource *resource;
|
2011-11-15 08:58:34 -05:00
|
|
|
|
2013-07-02 14:34:42 -04:00
|
|
|
resource = wl_resource_create(client, interface, -1, id);
|
2013-07-02 15:39:03 -04:00
|
|
|
if (resource == NULL)
|
|
|
|
|
wl_client_post_no_memory(client);
|
|
|
|
|
else
|
|
|
|
|
wl_resource_set_implementation(resource,
|
|
|
|
|
implementation, data, NULL);
|
2011-11-15 08:58:34 -05:00
|
|
|
|
2013-06-27 20:09:20 -05:00
|
|
|
return resource;
|
2011-11-15 08:58:34 -05:00
|
|
|
}
|
2012-05-29 17:37:02 +02:00
|
|
|
|
2024-06-29 15:05:00 +03:00
|
|
|
WL_DEPRECATED
|
2013-07-02 14:34:42 -04:00
|
|
|
struct wl_resource *
|
|
|
|
|
wl_client_new_object(struct wl_client *client,
|
|
|
|
|
const struct wl_interface *interface,
|
2024-06-29 15:05:00 +03:00
|
|
|
const void *implementation, void *data);
|
2013-07-02 14:34:42 -04:00
|
|
|
|
|
|
|
|
WL_EXPORT struct wl_resource *
|
|
|
|
|
wl_client_new_object(struct wl_client *client,
|
|
|
|
|
const struct wl_interface *interface,
|
|
|
|
|
const void *implementation, void *data)
|
2012-05-29 17:37:02 +02:00
|
|
|
{
|
2013-07-02 14:34:42 -04:00
|
|
|
struct wl_resource *resource;
|
|
|
|
|
|
|
|
|
|
resource = wl_resource_create(client, interface, -1, 0);
|
2013-07-02 15:39:03 -04:00
|
|
|
if (resource == NULL)
|
|
|
|
|
wl_client_post_no_memory(client);
|
|
|
|
|
else
|
|
|
|
|
wl_resource_set_implementation(resource,
|
|
|
|
|
implementation, data, NULL);
|
2013-07-02 14:34:42 -04:00
|
|
|
|
|
|
|
|
return resource;
|
2012-05-29 17:37:02 +02:00
|
|
|
}
|
2013-07-08 18:45:41 -04:00
|
|
|
|
2021-10-25 04:34:49 +02:00
|
|
|
/** 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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-29 15:05:00 +03:00
|
|
|
WL_DEPRECATED
|
2013-07-08 18:45:41 -04:00
|
|
|
struct wl_global *
|
|
|
|
|
wl_display_add_global(struct wl_display *display,
|
|
|
|
|
const struct wl_interface *interface,
|
2024-06-29 15:05:00 +03:00
|
|
|
void *data, wl_global_bind_func_t bind);
|
2013-07-08 18:45:41 -04:00
|
|
|
|
|
|
|
|
WL_EXPORT struct wl_global *
|
|
|
|
|
wl_display_add_global(struct wl_display *display,
|
|
|
|
|
const struct wl_interface *interface,
|
|
|
|
|
void *data, wl_global_bind_func_t bind)
|
|
|
|
|
{
|
|
|
|
|
return wl_global_create(display, interface, interface->version, data, bind);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-29 15:05:00 +03:00
|
|
|
WL_DEPRECATED
|
2013-07-08 18:45:41 -04:00
|
|
|
void
|
|
|
|
|
wl_display_remove_global(struct wl_display *display,
|
2024-06-29 15:05:00 +03:00
|
|
|
struct wl_global *global);
|
2013-07-08 18:45:41 -04:00
|
|
|
|
|
|
|
|
WL_EXPORT void
|
|
|
|
|
wl_display_remove_global(struct wl_display *display, struct wl_global *global)
|
|
|
|
|
{
|
|
|
|
|
wl_global_destroy(global);
|
|
|
|
|
}
|
2013-08-06 20:05:53 +02:00
|
|
|
|
2015-01-02 18:29:16 -08:00
|
|
|
/** \endcond */
|
|
|
|
|
|
2015-01-24 09:24:23 -06:00
|
|
|
/* Functions at the end of this file are deprecated. Instead of adding new
|
|
|
|
|
* code here, add it before the comment above that states:
|
|
|
|
|
* Deprecated functions below.
|
2013-11-13 21:11:17 -08:00
|
|
|
*/
|