aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE2
-rw-r--r--README.md85
-rw-r--r--examples/support/config.c5
-rw-r--r--examples/support/ini.c2
-rw-r--r--include/wlr/types/wlr_output.h2
-rw-r--r--include/wlr/types/wlr_xdg_shell.h10
-rw-r--r--include/wlr/types/wlr_xdg_shell_v6.h10
-rw-r--r--include/wlr/xwayland.h13
-rw-r--r--protocol/meson.build9
-rw-r--r--rootston/config.c5
-rw-r--r--rootston/ini.c2
-rw-r--r--rootston/xwayland.c48
-rw-r--r--xwayland/xwm.c82
13 files changed, 184 insertions, 91 deletions
diff --git a/LICENSE b/LICENSE
index da397236..b75a8c40 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2017 Drew DeVault
+Copyright (c) 2017, 2018 Drew DeVault
Copyright (c) 2014 Jari Vetoniemi
Permission is hereby granted, free of charge, to any person obtaining a copy of
diff --git a/README.md b/README.md
index a0160ce9..d65949da 100644
--- a/README.md
+++ b/README.md
@@ -1,49 +1,100 @@
# wlroots
-Pluggable, composable modules for building a
-[Wayland](http://wayland.freedesktop.org/) compositor.
+Pluggable, composable, unopinionated modules for building a
+[Wayland](http://wayland.freedesktop.org/) compositor; or about 40,000 lines of
+code you were going to write anyway.
-This is a WIP: [status](https://github.com/swaywm/wlroots/issues/9)
+- wlroots provides backends that abstract the underlying display and input
+ hardware, including KMS/DRM, libinput, Wayland, X11, and headless backends,
+ plus any custom backends you choose to write, which can all be created or
+ destroyed at runtime and used in concert with each other.
+- wlroots provides unopinionated, mostly standalone implementations of many
+ Wayland interfaces, both from wayland.xml and various protocol extensions.
+ We also promote the standardization of portable extensions across
+ many compositors.
+- wlroots provides several powerful, standalone, and optional tools that
+ implement components common to many compositors, such as the arrangement of
+ outputs in physical space.
+- wlroots provides an Xwayland abstraction that allows you to have excellent
+ Xwayland support without worrying about writing your own X11 window manager
+ on top of writing your compositor.
+- wlroots provides a renderer abstraction that simple compositors can use to
+ avoid writing GL code directly, but which steps out of the way when your
+ needs demand custom rendering code.
-## Contributing
+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
+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.
+
+**Status**: prior to 1.0 the API is not stable, but we've done most of the work
+and various projects are using wlroots to build Wayland compositors with.
-See [CONTRIBUTING.md](https://github.com/swaywm/wlroots/blob/master/CONTRIBUTING.md)
+wlroots is developed under the direction of the
+[sway](https://github.com/swaywm/sway) project. A variety of wrapper libraries
+[are available](https://github.com/swaywm) for using it with your favorite
+programming language.
## Building
Install dependencies:
+* meson
* wayland
* wayland-protocols
* EGL
* GLESv2
-* DRM
+* libdrm
* GBM
* libinput
+* xkbcommon
* udev
* pixman
* systemd (optional, for logind support)
* elogind (optional, for logind support on systems without systemd)
* libcap (optional, for capability support)
-* asciidoc (optional, for man pages)
+
+If you choose to enable X11 support:
+
+* xkb
+* xkb-composite
+* xkb-xfixes
+* xkb-image
+* xkb-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)
Run these commands:
meson build
ninja -C build
-(On FreeBSD, you need to pass an extra flag to prevent a linking error: `meson build -D b_lundef=false`)
+On FreeBSD, you need to pass an extra flag to prevent a linking error:
+`meson build -D b_lundef=false`.
-## Running the Reference Compositor
+Install like so:
-wlroots comes with a reference compositor called rootston that demonstrates the
-features of the library.
+ sudo ninja -C build install
-After building, run rootston from a terminal or VT with:
+## Running the test compositor
- ./build/rootston/rootston
+wlroots comes with a test compositor called rootston, which demonstrates the
+features of the library and is used as a testbed for the development of the
+library. It may also be useful as a reference for understanding how to use
+various wlroots features.
+
+If you followed the build instructions above the rootston executable can be
+found at `./build/rootston/rootston`. To use it, refer to the example config at
+[./rootston/rootston.ini.example](https://github.com/swaywm/wlroots/blob/master/rootston/rootston.ini.example)
+and place a config file of your own at `rootston.ini` in the working directory
+(or in an arbitrary location via `rootston -C`). Other options are available,
+refer to `rootston -h`.
+
+## Contributing
-Now you can run windows in the compositor from the command line or by
-configuring bindings in your
-[`rootston.ini`](https://github.com/swaywm/wlroots/blob/master/rootston/rootston.ini.example)
-file.
+See [CONTRIBUTING.md](https://github.com/swaywm/wlroots/blob/master/CONTRIBUTING.md).
diff --git a/examples/support/config.c b/examples/support/config.c
index f0efa594..319be31a 100644
--- a/examples/support/config.c
+++ b/examples/support/config.c
@@ -202,7 +202,10 @@ struct example_config *parse_args(int argc, char *argv[]) {
char cwd[MAXPATHLEN];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
char buf[MAXPATHLEN];
- snprintf(buf, MAXPATHLEN, "%s/%s", cwd, "wlr-example.ini");
+ if (snprintf(buf, MAXPATHLEN, "%s/%s", cwd, "wlr-example.ini") >= MAXPATHLEN) {
+ wlr_log(L_ERROR, "config path too long");
+ exit(1);
+ }
config->config_path = strdup(buf);
} else {
wlr_log(L_ERROR, "could not get cwd");
diff --git a/examples/support/ini.c b/examples/support/ini.c
index 6be9c44a..6bc1eae6 100644
--- a/examples/support/ini.c
+++ b/examples/support/ini.c
@@ -64,7 +64,7 @@ static char* find_chars_or_comment(const char* s, const char* chars)
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
static char* strncpy0(char* dest, const char* src, size_t size)
{
- strncpy(dest, src, size);
+ strncpy(dest, src, size-1);
dest[size - 1] = '\0';
return dest;
}
diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h
index cc03452d..cef3fc5d 100644
--- a/include/wlr/types/wlr_output.h
+++ b/include/wlr/types/wlr_output.h
@@ -55,7 +55,7 @@ struct wlr_output {
struct wl_global *wl_global;
struct wl_list wl_resources;
- char name[16];
+ char name[24];
char make[48];
char model[16];
char serial[16];
diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h
index faf398a7..5046339a 100644
--- a/include/wlr/types/wlr_xdg_shell.h
+++ b/include/wlr/types/wlr_xdg_shell.h
@@ -102,6 +102,16 @@ struct wlr_xdg_surface_configure {
struct wlr_xdg_toplevel_state *toplevel_state;
};
+/**
+ * An xdg-surface is a user interface element requiring management by the
+ * compositor. An xdg-surface alone isn't useful, a role should be assigned to
+ * it in order to map it.
+ *
+ * When a surface has a role and is ready to be displayed, the `map` event is
+ * emitted. When a surface should no longer be displayed, the `unmap` event is
+ * emitted. The `unmap` event is guaranted to be emitted before the `destroy`
+ * event if the view is destroyed when mapped.
+ */
struct wlr_xdg_surface {
struct wlr_xdg_client *client;
struct wl_resource *resource;
diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h
index 337d96ab..a315c4d9 100644
--- a/include/wlr/types/wlr_xdg_shell_v6.h
+++ b/include/wlr/types/wlr_xdg_shell_v6.h
@@ -90,6 +90,16 @@ struct wlr_xdg_toplevel_v6_state {
uint32_t min_width, min_height;
};
+/**
+ * An xdg-surface is a user interface element requiring management by the
+ * compositor. An xdg-surface alone isn't useful, a role should be assigned to
+ * it in order to map it.
+ *
+ * When a surface has a role and is ready to be displayed, the `map` event is
+ * emitted. When a surface should no longer be displayed, the `unmap` event is
+ * emitted. The `unmap` event is guaranted to be emitted before the `destroy`
+ * event if the view is destroyed when mapped.
+ */
struct wlr_xdg_toplevel_v6 {
struct wl_resource *resource;
struct wlr_xdg_surface_v6 *base;
diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h
index 1fad54d1..11aedc37 100644
--- a/include/wlr/xwayland.h
+++ b/include/wlr/xwayland.h
@@ -75,6 +75,15 @@ struct wlr_xwayland_surface_size_hints {
uint32_t win_gravity;
};
+/**
+ * An Xwayland user interface component. It has an absolute position in
+ * layout-local coordinates.
+ *
+ * When a surface is ready to be displayed, the `map` event is emitted. When a
+ * surface should no longer be displayed, the `unmap` event is emitted. The
+ * `unmap` event is guaranted to be emitted before the `destroy` event if the
+ * view is destroyed when mapped.
+ */
struct wlr_xwayland_surface {
xcb_window_t window_id;
struct wlr_xwm *xwm;
@@ -89,7 +98,6 @@ struct wlr_xwayland_surface {
uint16_t saved_width, saved_height;
bool override_redirect;
bool mapped;
- bool added;
char *title;
char *class;
@@ -116,8 +124,7 @@ struct wlr_xwayland_surface {
// _NET_WM_STATE
bool fullscreen;
- bool maximized_vert;
- bool maximized_horz;
+ bool maximized_vert, maximized_horz;
bool has_alpha;
diff --git a/protocol/meson.build b/protocol/meson.build
index bdbde96a..4730baf7 100644
--- a/protocol/meson.build
+++ b/protocol/meson.build
@@ -8,10 +8,17 @@ wayland_scanner_server = generator(
arguments: ['server-header', '@INPUT@', '@OUTPUT@'],
)
+# should check wayland_scanner's version, but it is hard to get
+if wayland_server.version().version_compare('>=1.14.91')
+ code_type = 'private-code'
+else
+ code_type = 'code'
+endif
+
wayland_scanner_code = generator(
wayland_scanner,
output: '@BASENAME@-protocol.c',
- arguments: ['code', '@INPUT@', '@OUTPUT@'],
+ arguments: [code_type, '@INPUT@', '@OUTPUT@'],
)
wayland_scanner_client = generator(
diff --git a/rootston/config.c b/rootston/config.c
index 0883f6d4..67bf83e9 100644
--- a/rootston/config.c
+++ b/rootston/config.c
@@ -418,7 +418,10 @@ struct roots_config *roots_config_create_from_args(int argc, char *argv[]) {
char cwd[MAXPATHLEN];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
char buf[MAXPATHLEN];
- snprintf(buf, MAXPATHLEN, "%s/%s", cwd, "rootston.ini");
+ if (snprintf(buf, MAXPATHLEN, "%s/%s", cwd, "rootston.ini") >= MAXPATHLEN) {
+ wlr_log(L_ERROR, "config path too long");
+ exit(1);
+ }
config->config_path = strdup(buf);
} else {
wlr_log(L_ERROR, "could not get cwd");
diff --git a/rootston/ini.c b/rootston/ini.c
index 56cc9ea6..f515dd38 100644
--- a/rootston/ini.c
+++ b/rootston/ini.c
@@ -64,7 +64,7 @@ static char* find_chars_or_comment(const char* s, const char* chars)
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
static char* strncpy0(char* dest, const char* src, size_t size)
{
- strncpy(dest, src, size);
+ strncpy(dest, src, size-1);
dest[size - 1] = '\0';
return dest;
}
diff --git a/rootston/xwayland.c b/rootston/xwayland.c
index 27a27b65..b7dbab54 100644
--- a/rootston/xwayland.c
+++ b/rootston/xwayland.c
@@ -228,19 +228,31 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
static void handle_map(struct wl_listener *listener, void *data) {
struct roots_xwayland_surface *roots_surface =
wl_container_of(listener, roots_surface, map);
- struct wlr_xwayland_surface *xsurface = data;
+ struct wlr_xwayland_surface *surface = data;
struct roots_view *view = roots_surface->view;
- view->x = xsurface->x;
- view->y = xsurface->y;
- view->width = xsurface->surface->current->width;
- view->height = xsurface->surface->current->height;
-
- view_map(view, xsurface->surface);
+ view->x = surface->x;
+ view->y = surface->y;
+ view->width = surface->surface->current->width;
+ view->height = surface->surface->current->height;
roots_surface->surface_commit.notify = handle_surface_commit;
- wl_signal_add(&xsurface->surface->events.commit,
+ wl_signal_add(&surface->surface->events.commit,
&roots_surface->surface_commit);
+
+ view_map(view, surface->surface);
+
+ if (!surface->override_redirect) {
+ if (surface->decorations == WLR_XWAYLAND_SURFACE_DECORATIONS_ALL) {
+ view->decorated = true;
+ view->border_width = 4;
+ view->titlebar_height = 12;
+ }
+
+ view_setup(view);
+ } else {
+ view_initial_focus(view);
+ }
}
static void handle_unmap(struct wl_listener *listener, void *data) {
@@ -289,10 +301,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
wl_signal_add(&surface->events.request_fullscreen,
&roots_surface->request_fullscreen);
- roots_surface->surface_commit.notify = handle_surface_commit;
- wl_signal_add(&surface->surface->events.commit,
- &roots_surface->surface_commit);
-
struct roots_view *view = view_create(desktop);
if (view == NULL) {
free(roots_surface);
@@ -301,8 +309,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
view->type = ROOTS_XWAYLAND_VIEW;
view->x = (double)surface->x;
view->y = (double)surface->y;
- view->width = surface->surface->current->width;
- view->height = surface->surface->current->height;
view->xwayland_surface = surface;
view->roots_xwayland_surface = roots_surface;
@@ -315,18 +321,4 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
view->close = close;
view->destroy = destroy;
roots_surface->view = view;
-
- view_map(view, surface->surface);
-
- if (!surface->override_redirect) {
- if (surface->decorations == WLR_XWAYLAND_SURFACE_DECORATIONS_ALL) {
- view->decorated = true;
- view->border_width = 4;
- view->titlebar_height = 12;
- }
-
- view_setup(view);
- } else {
- view_initial_focus(view);
- }
}
diff --git a/xwayland/xwm.c b/xwayland/xwm.c
index bad40117..77dc0797 100644
--- a/xwayland/xwm.c
+++ b/xwayland/xwm.c
@@ -109,7 +109,7 @@ static int xwayland_surface_handle_ping_timeout(void *data) {
return 1;
}
-static struct wlr_xwayland_surface *wlr_xwayland_surface_create(
+static struct wlr_xwayland_surface *xwayland_surface_create(
struct wlr_xwm *xwm, xcb_window_t window_id, int16_t x, int16_t y,
uint16_t width, uint16_t height, bool override_redirect) {
struct wlr_xwayland_surface *surface =
@@ -171,6 +171,8 @@ static struct wlr_xwayland_surface *wlr_xwayland_surface_create(
return NULL;
}
+ wlr_signal_emit_safe(&xwm->xwayland->events.new_surface, surface);
+
return surface;
}
@@ -273,8 +275,12 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) {
i, property);
}
+static void xsurface_unmap(struct wlr_xwayland_surface *surface);
+
static void wlr_xwayland_surface_destroy(
struct wlr_xwayland_surface *xsurface) {
+ xsurface_unmap(xsurface);
+
wlr_signal_emit_safe(&xsurface->events.destroy, xsurface);
if (xsurface == xsurface->xwm->focus_surface) {
@@ -293,6 +299,8 @@ static void wlr_xwayland_surface_destroy(
wlr_surface_set_role_committed(xsurface->surface, NULL, NULL);
}
+ wl_event_source_remove(xsurface->ping_timer);
+
free(xsurface->title);
free(xsurface->class);
free(xsurface->instance);
@@ -613,27 +621,22 @@ static void read_surface_property(struct wlr_xwm *xwm,
static void handle_surface_commit(struct wlr_surface *wlr_surface,
void *role_data) {
- struct wlr_xwayland_surface *xsurface = role_data;
+ struct wlr_xwayland_surface *surface = role_data;
- if (!xsurface->added &&
- wlr_surface_has_buffer(xsurface->surface) &&
- xsurface->mapped) {
- wlr_signal_emit_safe(&xsurface->xwm->xwayland->events.new_surface, xsurface);
- xsurface->added = true;
+ if (!surface->mapped && wlr_surface_has_buffer(surface->surface)) {
+ wlr_signal_emit_safe(&surface->events.map, surface);
+ surface->mapped = true;
}
}
static void handle_surface_destroy(struct wl_listener *listener, void *data) {
- struct wlr_xwayland_surface *xsurface =
- wl_container_of(listener, xsurface, surface_destroy);
-
- xsurface->surface = NULL;
- // TODO destroy xwayland surface?
+ struct wlr_xwayland_surface *surface =
+ wl_container_of(listener, surface, surface_destroy);
+ xsurface_unmap(surface);
}
static void xwm_map_shell_surface(struct wlr_xwm *xwm,
- struct wlr_xwayland_surface *xsurface,
- struct wlr_surface *surface) {
+ struct wlr_xwayland_surface *xsurface, struct wlr_surface *surface) {
xsurface->surface = surface;
// read all surface properties
@@ -660,15 +663,40 @@ static void xwm_map_shell_surface(struct wlr_xwm *xwm,
xsurface->surface_destroy.notify = handle_surface_destroy;
wl_signal_add(&surface->events.destroy, &xsurface->surface_destroy);
+}
- xsurface->mapped = true;
- wlr_signal_emit_safe(&xsurface->events.map, xsurface);
+static void xsurface_unmap(struct wlr_xwayland_surface *surface) {
+ if (surface->mapped) {
+ surface->mapped = false;
+ wlr_signal_emit_safe(&surface->events.unmap, surface);
+ }
+
+ if (surface->surface_id) {
+ // Make sure we're not on the unpaired surface list or we
+ // could be assigned a surface during surface creation that
+ // was mapped before this unmap request.
+ wl_list_remove(&surface->unpaired_link);
+ surface->surface_id = 0;
+ }
+
+ if (surface->surface) {
+ wlr_surface_set_role_committed(surface->surface, NULL, NULL);
+ wl_list_remove(&surface->surface_destroy.link);
+ surface->surface = NULL;
+ }
}
static void xwm_handle_create_notify(struct wlr_xwm *xwm,
xcb_create_notify_event_t *ev) {
wlr_log(L_DEBUG, "XCB_CREATE_NOTIFY (%u)", ev->window);
- wlr_xwayland_surface_create(xwm, ev->window, ev->x, ev->y,
+
+ if (ev->window == xwm->window ||
+ ev->window == xwm->selection_window ||
+ ev->window == xwm->dnd_window) {
+ return;
+ }
+
+ xwayland_surface_create(xwm, ev->window, ev->x, ev->y,
ev->width, ev->height, ev->override_redirect);
}
@@ -778,25 +806,7 @@ static void xwm_handle_unmap_notify(struct wlr_xwm *xwm,
return;
}
- if (xsurface->mapped) {
- xsurface->mapped = false;
- wlr_signal_emit_safe(&xsurface->events.unmap, xsurface);
- }
-
- if (xsurface->surface_id) {
- // Make sure we're not on the unpaired surface list or we
- // could be assigned a surface during surface creation that
- // was mapped before this unmap request.
- wl_list_remove(&xsurface->unpaired_link);
- xsurface->surface_id = 0;
- }
-
- if (xsurface->surface) {
- wlr_surface_set_role_committed(xsurface->surface, NULL, NULL);
- wl_list_remove(&xsurface->surface_destroy.link);
- }
- xsurface->surface = NULL;
-
+ xsurface_unmap(xsurface);
xsurface_set_wm_state(xsurface, ICCCM_WITHDRAWN_STATE);
}