Commit d825a8f1 authored by Guido Gunther's avatar Guido Gunther
Browse files

Merge branch 'master' into f/phosh-private

parents f530a562 8d03bc91
image: archlinux
packages:
- clang
- ffmpeg
- libcap
- libinput
- libxkbcommon
- mesa
- meson
- pixman
- wayland
- wayland-protocols
- mesa
- libinput
- libxkbcommon
- xcb-util-image
- libcap
- pixman
- clang
sources:
- https://github.com/swaywm/wlroots
tasks:
......
......@@ -93,10 +93,10 @@ not use GNU extensions.
### Brackets
Brackets always go on the same line, including in functions.
Brackets always go on the same line, including in functions.
Always include brackets for if/while/for, even if it's a single statement.
```c
void function() {
void function(void) {
if (condition1) {
do_thing1();
}
......@@ -114,7 +114,7 @@ void function() {
Indentations are a single tab.
For long lines that need to be broken, the continuation line should be indented
with an additional tab.
with an additional tab.
If the line being broken is opening a new block (functions, if, while, etc.),
the continuation line should be indented with two tabs, so they can't be
misread as being part of the block.
......@@ -139,9 +139,10 @@ breaking points so your code is easy to read.
### Names
Function and type names should be prefixed with `wlr_submodule_` (e.g. `struct
wlr_drm_plane`, `wlr_output_set_cursor`). For static functions and types local
to a file, the names chosen aren't as important.
Global function and type names should be prefixed with `wlr_submodule_` (e.g.
`struct wlr_output`, `wlr_output_set_cursor`). For static functions and
types local to a file, the names chosen aren't as important. Local function
names shouldn't have a `wlr_` prefix.
For include guards, use the header's filename relative to include. Uppercase
all of the characters, and replace any invalid characters with an underscore.
......@@ -170,7 +171,7 @@ Try to keep the use of macros to a minimum, especially if a function can do the
job. If you do need to use them, try to keep them close to where they're being
used and `#undef` them after.
## Example
### Example
```c
struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
......@@ -191,13 +192,13 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
struct wlr_session *session = wlr_session_create(display);
if (!session) {
wlr_log(L_ERROR, "Failed to start a DRM session");
wlr_log(WLR_ERROR, "Failed to start a DRM session");
return NULL;
}
int gpu = wlr_session_find_gpu(session);
if (gpu == -1) {
wlr_log(L_ERROR, "Failed to open DRM device");
wlr_log(WLR_ERROR, "Failed to open DRM device");
goto error_session;
}
......@@ -231,3 +232,125 @@ error_session:
return NULL;
}
```
## Wayland protocol implementation
Each protocol generally lives in a file with the same name, usually containing
at least one struct for each interface in the protocol. For instance,
`xdg_shell` lives in `types/wlr_xdg_shell.h` and has a `wlr_xdg_surface` struct.
### Globals
Global interfaces generally have public constructors and destructors. Their
struct has a field holding the `wl_global` itself, a list of resources clients
created by binding to the global, a destroy signal and a `wl_display` destroy
listener. Example:
```c
struct wlr_compositor {
struct wl_global *global;
struct wl_list resources;
struct wl_listener display_destroy;
struct {
struct wl_signal new_surface;
struct wl_signal destroy;
} events;
};
```
When the destructor is called, it should emit the destroy signal, remove the
display destroy listener, destroy the `wl_global`, destroy all bound resources
and then destroy the struct.
### Resources
Resources are the representation of Wayland objects on the compositor side. They
generally have an associated struct, called the _object struct_, stored in their
`user_data` field.
Object structs can be retrieved from resources via `wl_resource_get_data`. To
prevent bad casts, a safe helper function checking the type of the resource is
used:
```c
static const struct wl_surface_interface surface_impl;
struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &wl_surface_interface,
&surface_impl));
return wl_resource_get_user_data(resource);
}
```
### Destroying resources
Object structs should only be destroyed when their resource is destroyed, ie.
in the resource destroy handler (set with `wl_resource_set_implementation`).
Destructor requests should only call `wl_resource_destroy`.
The compositor should not destroy resources on its own.
### Inert resources
Some resources can become inert in situations described in the protocol or when
the compositor decides to get rid of them. All requests made to inert resources
should be ignored, except the destructor. This is achieved by:
1. When the resource becomes inert: destroy the object struct and call
`wl_resource_set_user_data(resource, NULL)`. Do not destroy the resource.
2. For each request made to a resource that can be inert: add a NULL check to
ignore the request if the resource is inert.
3. When the client calls the destructor request on the resource: call
`wl_resource_destroy(resource)` as usual.
4. When the resource is destroyed, if the resource isn't inert, destroy the
object struct.
Example:
```c
// Handles the destroy request
static void subsurface_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
// Handles a regular request
static void subsurface_set_position(struct wl_client *client,
struct wl_resource *resource, int32_t x, int32_t y) {
struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
if (subsurface == NULL) {
return;
}
}
// Destroys the wlr_subsurface struct
static void subsurface_destroy(struct wlr_subsurface *subsurface) {
if (subsurface == NULL) {
return;
}
wl_resource_set_user_data(subsurface->resource, NULL);
free(subsurface);
}
// Resource destroy listener
static void subsurface_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
subsurface_destroy(subsurface);
}
// Makes the resource inert
static void subsurface_handle_surface_destroy(struct wl_listener *listener,
void *data) {
struct wlr_subsurface *subsurface =
wl_container_of(listener, subsurface, surface_destroy);
subsurface_destroy(subsurface);
}
```
......@@ -25,7 +25,7 @@ code you were going to write anyway.
wlroots implements a huge variety of Wayland compositor features and implements
them *right*, so you can focus on the features that make your compositor
unique. By using wlroots, you get high performance, excellent hardware
compatability, broad support for many wayland interfaces, and comfortable
compatibility, broad support for many wayland interfaces, and comfortable
development tools - or any subset of these features you like, because all of
them work independently of one another and freely compose with anything you want
to implement yourself.
......@@ -59,15 +59,15 @@ Install dependencies:
If you choose to enable X11 support:
* xkb
* xkb-composite
* xkb-xfixes
* xkb-image
* xkb-render
* xcb
* xcb-composite
* xcb-xfixes
* xcb-image
* xcb-render
* x11-xcb
* xcb-errors (optional, for improved error reporting)
* x11-icccm (optional, for improved Xwayland introspection)
* xkb-xcb (optional, for improved keyboard handling on the X11 backend)
* xcb-xkb (optional, for improved keyboard handling on the X11 backend)
Run these commands:
......
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <errno.h>
#include <libinput.h>
......@@ -6,6 +7,7 @@
#include <unistd.h>
#include <wayland-server.h>
#include <wlr/backend/drm.h>
#include <wlr/backend/headless.h>
#include <wlr/backend/interface.h>
#include <wlr/backend/libinput.h>
#include <wlr/backend/multi.h>
......@@ -63,15 +65,16 @@ static size_t parse_outputs_env(const char *name) {
char *end;
int outputs = (int)strtol(outputs_str, &end, 10);
if (*end || outputs < 0) {
wlr_log(L_ERROR, "%s specified with invalid integer, ignoring", name);
wlr_log(WLR_ERROR, "%s specified with invalid integer, ignoring", name);
return 1;
}
return outputs;
}
static struct wlr_backend *attempt_wl_backend(struct wl_display *display) {
struct wlr_backend *backend = wlr_wl_backend_create(display, NULL);
static struct wlr_backend *attempt_wl_backend(struct wl_display *display,
wlr_renderer_create_func_t create_renderer_func) {
struct wlr_backend *backend = wlr_wl_backend_create(display, NULL, create_renderer_func);
if (backend == NULL) {
return NULL;
}
......@@ -86,8 +89,8 @@ static struct wlr_backend *attempt_wl_backend(struct wl_display *display) {
#ifdef WLR_HAS_X11_BACKEND
static struct wlr_backend *attempt_x11_backend(struct wl_display *display,
const char *x11_display) {
struct wlr_backend *backend = wlr_x11_backend_create(display, x11_display);
const char *x11_display, wlr_renderer_create_func_t create_renderer_func) {
struct wlr_backend *backend = wlr_x11_backend_create(display, x11_display, create_renderer_func);
if (backend == NULL) {
return NULL;
}
......@@ -101,16 +104,128 @@ static struct wlr_backend *attempt_x11_backend(struct wl_display *display,
}
#endif
struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
static struct wlr_backend *attempt_headless_backend(
struct wl_display *display, wlr_renderer_create_func_t create_renderer_func) {
struct wlr_backend *backend = wlr_headless_backend_create(display, create_renderer_func);
if (backend == NULL) {
return NULL;
}
size_t outputs = parse_outputs_env("WLR_HEADLESS_OUTPUTS");
for (size_t i = 0; i < outputs; ++i) {
wlr_headless_add_output(backend, 1280, 720);
}
return backend;
}
static struct wlr_backend *attempt_drm_backend(struct wl_display *display,
struct wlr_backend *backend, struct wlr_session *session,
wlr_renderer_create_func_t create_renderer_func) {
int gpus[8];
size_t num_gpus = wlr_session_find_gpus(session, 8, gpus);
struct wlr_backend *primary_drm = NULL;
wlr_log(WLR_INFO, "Found %zu GPUs", num_gpus);
for (size_t i = 0; i < num_gpus; ++i) {
struct wlr_backend *drm = wlr_drm_backend_create(display, session,
gpus[i], primary_drm, create_renderer_func);
if (!drm) {
wlr_log(WLR_ERROR, "Failed to open DRM device %d", gpus[i]);
continue;
}
if (!primary_drm) {
primary_drm = drm;
}
wlr_multi_backend_add(backend, drm);
}
return primary_drm;
}
static struct wlr_backend *attempt_backend_by_name(struct wl_display *display,
struct wlr_backend *backend, struct wlr_session **session,
const char *name, wlr_renderer_create_func_t create_renderer_func) {
if (strcmp(name, "wayland") == 0) {
return attempt_wl_backend(display, create_renderer_func);
#ifdef WLR_HAS_X11_BACKEND
} else if (strcmp(name, "x11") == 0) {
return attempt_x11_backend(display, NULL, create_renderer_func);
#endif
} else if (strcmp(name, "headless") == 0) {
return attempt_headless_backend(display, create_renderer_func);
} else if (strcmp(name, "drm") == 0 || strcmp(name, "libinput") == 0) {
// DRM and libinput need a session
*session = wlr_session_create(display);
if (!*session) {
wlr_log(WLR_ERROR, "failed to start a session");
return NULL;
}
if (strcmp(name, "libinput") == 0) {
return wlr_libinput_backend_create(display, *session);
} else {
return attempt_drm_backend(display, backend, *session, create_renderer_func);
}
}
wlr_log(WLR_ERROR, "unrecognized backend '%s'", name);
return NULL;
}
struct wlr_backend *wlr_backend_autocreate(struct wl_display *display,
wlr_renderer_create_func_t create_renderer_func) {
struct wlr_backend *backend = wlr_multi_backend_create(display);
if (!backend) {
wlr_log(L_ERROR, "could not allocate multibackend");
wlr_log(WLR_ERROR, "could not allocate multibackend");
return NULL;
}
struct wlr_session *session = NULL;
char *names = getenv("WLR_BACKENDS");
if (names) {
names = strdup(names);
if (names == NULL) {
wlr_log(WLR_ERROR, "allocation failed");
wlr_backend_destroy(backend);
return NULL;
}
char *saveptr;
char *name = strtok_r(names, ",", &saveptr);
while (name != NULL) {
struct wlr_backend *subbackend =
attempt_backend_by_name(display, backend, &session, name, create_renderer_func);
if (subbackend == NULL) {
wlr_log(WLR_ERROR, "failed to start backend '%s'", name);
wlr_backend_destroy(backend);
wlr_session_destroy(session);
free(names);
return NULL;
}
if (!wlr_multi_backend_add(backend, subbackend)) {
wlr_log(WLR_ERROR, "failed to add backend '%s'", name);
wlr_backend_destroy(backend);
wlr_session_destroy(session);
free(names);
return NULL;
}
name = strtok_r(NULL, ",", &saveptr);
}
free(names);
return backend;
}
if (getenv("WAYLAND_DISPLAY") || getenv("_WAYLAND_DISPLAY") ||
getenv("WAYLAND_SOCKET")) {
struct wlr_backend *wl_backend = attempt_wl_backend(display);
struct wlr_backend *wl_backend = attempt_wl_backend(display,
create_renderer_func);
if (wl_backend) {
wlr_multi_backend_add(backend, wl_backend);
return backend;
......@@ -121,7 +236,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
const char *x11_display = getenv("DISPLAY");
if (x11_display) {
struct wlr_backend *x11_backend =
attempt_x11_backend(display, x11_display);
attempt_x11_backend(display, x11_display, create_renderer_func);
if (x11_backend) {
wlr_multi_backend_add(backend, x11_backend);
return backend;
......@@ -130,48 +245,29 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
#endif
// Attempt DRM+libinput
struct wlr_session *session = wlr_session_create(display);
session = wlr_session_create(display);
if (!session) {
wlr_log(L_ERROR, "Failed to start a DRM session");
wlr_log(WLR_ERROR, "Failed to start a DRM session");
wlr_backend_destroy(backend);
return NULL;
}
struct wlr_backend *libinput = wlr_libinput_backend_create(display, session);
if (libinput) {
wlr_multi_backend_add(backend, libinput);
} else {
wlr_log(L_ERROR, "Failed to start libinput backend");
if (!libinput) {
wlr_log(WLR_ERROR, "Failed to start libinput backend");
wlr_backend_destroy(backend);
wlr_session_destroy(session);
return NULL;
}
wlr_multi_backend_add(backend, libinput);
int gpus[8];
size_t num_gpus = wlr_session_find_gpus(session, 8, gpus);
struct wlr_backend *primary_drm = NULL;
wlr_log(L_INFO, "Found %zu GPUs", num_gpus);
for (size_t i = 0; i < num_gpus; ++i) {
struct wlr_backend *drm = wlr_drm_backend_create(display, session,
gpus[i], primary_drm);
if (!drm) {
wlr_log(L_ERROR, "Failed to open DRM device");
continue;
}
if (!primary_drm) {
primary_drm = drm;
}
wlr_multi_backend_add(backend, drm);
}
struct wlr_backend *primary_drm =
attempt_drm_backend(display, backend, session, create_renderer_func);
if (!primary_drm) {
wlr_log(L_ERROR, "Failed to open any DRM device");
wlr_log(WLR_ERROR, "Failed to open any DRM device");
wlr_backend_destroy(libinput);
wlr_session_destroy(session);
wlr_backend_destroy(backend);
wlr_session_destroy(session);
return NULL;
}
......
......@@ -17,7 +17,7 @@ static void atomic_begin(struct wlr_drm_crtc *crtc, struct atomic *atom) {
if (!crtc->atomic) {
crtc->atomic = drmModeAtomicAlloc();
if (!crtc->atomic) {
wlr_log_errno(L_ERROR, "Allocation failed");
wlr_log_errno(WLR_ERROR, "Allocation failed");
atom->failed = true;
return;
}
......@@ -35,7 +35,7 @@ static bool atomic_end(int drm_fd, struct atomic *atom) {
uint32_t flags = DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_NONBLOCK;
if (drmModeAtomicCommit(drm_fd, atom->req, flags, NULL)) {
wlr_log_errno(L_ERROR, "Atomic test failed");
wlr_log_errno(WLR_ERROR, "Atomic test failed");
drmModeAtomicSetCursor(atom->req, atom->cursor);
return false;
}
......@@ -51,13 +51,13 @@ static bool atomic_commit(int drm_fd, struct atomic *atom,
int ret = drmModeAtomicCommit(drm_fd, atom->req, flags, conn);
if (ret) {
wlr_log_errno(L_ERROR, "%s: Atomic commit failed (%s)",
wlr_log_errno(WLR_ERROR, "%s: Atomic commit failed (%s)",
conn->output.name, modeset ? "modeset" : "pageflip");
// Try to commit without new changes
drmModeAtomicSetCursor(atom->req, atom->cursor);
if (drmModeAtomicCommit(drm_fd, atom->req, flags, conn)) {
wlr_log_errno(L_ERROR,
wlr_log_errno(WLR_ERROR,
"%s: Atomic commit without new changes failed (%s)",
conn->output.name, modeset ? "modeset" : "pageflip");
}
......@@ -70,7 +70,7 @@ static bool atomic_commit(int drm_fd, struct atomic *atom,
static inline void atomic_add(struct atomic *atom, uint32_t id, uint32_t prop, uint64_t val) {
if (!atom->failed && drmModeAtomicAddProperty(atom->req, id, prop, val) < 0) {
wlr_log_errno(L_ERROR, "Failed to add atomic DRM property");
wlr_log_errno(WLR_ERROR, "Failed to add atomic DRM property");
atom->failed = true;
}
}
......@@ -83,8 +83,8 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_plane *plane,
// The src_* properties are in 16.16 fixed point
atomic_add(atom, id, props->src_x, 0);
atomic_add(atom, id, props->src_y, 0);
atomic_add(atom, id, props->src_w, plane->surf.width << 16);
atomic_add(atom, id, props->src_h, plane->surf.height << 16);
atomic_add(atom, id, props->src_w, (uint64_t)plane->surf.width << 16);
atomic_add(atom, id, props->src_h, (uint64_t)plane->surf.height << 16);
atomic_add(atom, id, props->crtc_w, plane->surf.width);
atomic_add(atom, id, props->crtc_h, plane->surf.height);
atomic_add(atom, id, props->fb_id, fb_id);
......@@ -105,7 +105,7 @@ static bool atomic_crtc_pageflip(struct wlr_drm_backend *drm,
}
if (drmModeCreatePropertyBlob(drm->fd, mode, sizeof(*mode), &crtc->mode_id)) {
wlr_log_errno(L_ERROR, "Unable to create property blob");
wlr_log_errno(WLR_ERROR, "Unable to create property blob");
return false;
}
}
......@@ -219,7 +219,7 @@ static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm,
if (drmModeCreatePropertyBlob(drm->fd, gamma,
sizeof(struct drm_color_lut) * size, &crtc->gamma_lut)) {
wlr_log_errno(L_ERROR, "Unable to create property blob");
wlr_log_errno(WLR_ERROR, "Unable to create property blob");
return false;
}
......@@ -237,9 +237,9 @@ static uint32_t atomic_crtc_get_gamma_size(struct wlr_drm_backend *drm,
return legacy_iface.crtc_get_gamma_size(drm, crtc);
}
if (!wlr_drm_get_prop(drm->fd, crtc->id, crtc->props.gamma_lut_size,
if (!get_drm_prop(drm->fd, crtc->id, crtc->props.gamma_lut_size,
&gamma_lut_size)) {
wlr_log(L_ERROR, "Unable to get gamma lut size");
wlr_log(WLR_ERROR, "Unable to get gamma lut size");
return 0;
}
......
......@@ -15,20 +15,20 @@
#include "backend/drm/drm.h"
#include "util/signal.h"
static bool wlr_drm_backend_start(struct wlr_backend *backend) {
static bool backend_start(struct wlr_backend *backend) {
struct wlr_drm_backend *drm = (struct wlr_drm_backend *)backend;
wlr_drm_scan_connectors(drm);
scan_drm_connectors(drm);
return true;
}
static void wlr_drm_backend_destroy(struct wlr_backend *backend) {
static void backend_destroy(struct wlr_backend *backend) {
if (!backend) {
return;
}
struct wlr_drm_backend *drm = (struct wlr_drm_backend *)backend;
wlr_drm_restore_outputs(drm);
restore_drm_outputs(drm);
struct wlr_drm_connector *conn, *next;
wl_list_for_each_safe(conn, next, &drm->outputs, link) {
......@@ -41,23 +41,23 @@ static void wlr_drm_backend_destroy(struct wlr_backend *backend) {
wl_list_remove(&drm->session_signal.link);
wl_list_remove(&drm->drm_invalidated.link);
wlr_drm_resources_free(drm);
wlr_drm_renderer_finish(&drm->renderer);
finish_drm_resources(drm);
finish_drm_renderer(&drm->renderer);
wlr_session_close_file(drm->session, drm->fd);
wl_event_source_remove(drm->drm_event);
free(drm);
}
static struct wlr_renderer *wlr_drm_backend_get_renderer(
static struct wlr_renderer *backend_get_renderer(
struct wlr_backend *backend) {
struct wlr_drm_backend *drm = (struct wlr_drm_backend *)backend;
return drm->renderer.wlr_rend;
}
static struct wlr_backend_impl backend_impl = {
.start = wlr_drm_backend_start,
.destroy = wlr_drm_backend_destroy,
.get_renderer = wlr_drm_backend_get_renderer,
.start = backend_start,
.destroy = backend_destroy,
.get_renderer = backend_get_renderer,
};
bool wlr_backend_is_drm(struct wlr_backend *b) {
......@@ -70,15 +70,15 @@ static void session_signal(struct wl_listener *listener, void *data) {
struct wlr_session *session = data;
if (session->active) {
wlr_log(L_INFO, "DRM fd resumed");
wlr_drm_scan_connectors(drm);
wlr_log(WLR_INFO, "DRM fd resumed");
scan_drm_connectors(drm);
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->outputs, link){