mirror of
https://codeberg.org/dwl/dwl.git
synced 2025-12-16 18:03:19 +00:00
Merge branch 'main' into basic_damage_tracking
This commit is contained in:
commit
c2d75c24df
18
README.md
18
README.md
@ -2,7 +2,7 @@
|
||||
|
||||
Join us on our [Discord server](https://discord.gg/jJxZnrGPWN)!
|
||||
|
||||
dwl is a compact, hackable compositor for Wayland based on [wlroots](https://github.com/swaywm/wlroots). It is intended to fill the same space in the Wayland world that dwm does in X11, primarily in terms of philosophy, and secondarily in terms of functionality. Like dwm, dwl is:
|
||||
dwl is a compact, hackable compositor for Wayland based on [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots/). It is intended to fill the same space in the Wayland world that dwm does in X11, primarily in terms of philosophy, and secondarily in terms of functionality. Like dwm, dwl is:
|
||||
|
||||
- Easy to understand, hack on, and extend with patches
|
||||
- One C source file (or a very small number) configurable via `config.h`
|
||||
@ -54,16 +54,24 @@ dwl can be run on any of the backends supported by wlroots. This means you can r
|
||||
|
||||
When dwl is run with no arguments, it will launch the server and begin handling any shortcuts configured in `config.h`. There is no status bar or other decoration initially; these are instead clients that can be run within the Wayland session.
|
||||
|
||||
If you would like to run a script or command automatically at startup, you can specify the command using the `-s` option. The argument to this option will be parsed as a shell command (using `sh -c`) and can serve a similar function to `.xinitrc`. Unlike `.xinitrc`, the display server will not shut down when this process terminates. Instead, as dwl is shutting down, it will send this process a SIGTERM and wait for it to terminate (if it hasn't already). This makes it ideal for execing into a user service manager like [s6](https://skarnet.org/software/s6/), [anopa](https://jjacky.com/anopa/), [runit](http://smarden.org/runit/faq.html#userservices), or [`systemd --user`](https://wiki.archlinux.org/title/Systemd/User).
|
||||
If you would like to run a script or command automatically at startup, you can specify the command using the `-s` option. This command will be executed as a shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`, but differs in that the display server will not shut down when this process terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait for it to terminate (if it hasn't already). This makes it ideal for execing into a user service manager like [s6](https://skarnet.org/software/s6/), [anopa](https://jjacky.com/anopa/), [runit](http://smarden.org/runit/faq.html#userservices), or [`systemd --user`](https://wiki.archlinux.org/title/Systemd/User).
|
||||
|
||||
Note: The `-s` command is run as a *child process* of dwl, which means that it does not have the ability to affect the environment of dwl or of any processes that it spawns. If you need to set environment variables that affect the entire dwl session (such as `XDG_RUNTIME_DIR` in the note below), these must be set prior to running dwl.
|
||||
|
||||
Note: Wayland requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager such as `elogind` or `systemd-logind`. If your system doesn't do this automatically, you will need to configure it prior to launching `dwl`, e.g.:
|
||||
Note: The `-s` command is run as a *child process* of dwl, which means that it does not have the ability to affect the environment of dwl or of any processes that it spawns. If you need to set environment variables that affect the entire dwl session, these must be set prior to running dwl. For example, Wayland requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager such as `elogind` or `systemd-logind`. If your system doesn't do this automatically, you will need to configure it prior to launching `dwl`, e.g.:
|
||||
|
||||
export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u)
|
||||
mkdir -p $XDG_RUNTIME_DIR
|
||||
dwl
|
||||
|
||||
### Status information
|
||||
|
||||
Information about selected layouts, current window title, and selected/occupied/urgent tags is written to the stdin of the `-s` command (see the `printstatus()` function for details). This information can be used to populate an external status bar with a script that parses the information. Failing to read this information will cause dwl to block, so if you do want to run a startup command that does not consume the status information, you can close standard input with the `<&-` shell redirection, for example:
|
||||
|
||||
dwl -s 'foot --server <&-'
|
||||
|
||||
If your startup command is a shell script, you can achieve the same inside the script with the line
|
||||
|
||||
exec <&-
|
||||
|
||||
## Replacements for X applications
|
||||
|
||||
You can find a [list of Wayland applications on the sway wiki](https://github.com/swaywm/sway/wiki/i3-Migration-Guide).
|
||||
|
||||
43
client.h
43
client.h
@ -5,7 +5,7 @@
|
||||
* that they will simply compile out if the chosen #defines leave them unused.
|
||||
*/
|
||||
|
||||
/* Leave this function first; it's used in the others */
|
||||
/* Leave these functions first; they're used in the others */
|
||||
static inline int
|
||||
client_is_x11(Client *c)
|
||||
{
|
||||
@ -16,6 +16,16 @@ client_is_x11(Client *c)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline struct wlr_surface *
|
||||
client_surface(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return c->surface.xwayland->surface;
|
||||
#endif
|
||||
return c->surface.xdg->surface;
|
||||
}
|
||||
|
||||
/* The others */
|
||||
static inline void
|
||||
client_activate_surface(struct wlr_surface *s, int activated)
|
||||
@ -35,14 +45,12 @@ client_activate_surface(struct wlr_surface *s, int activated)
|
||||
static inline void
|
||||
client_for_each_surface(Client *c, wlr_surface_iterator_func_t fn, void *data)
|
||||
{
|
||||
wlr_surface_for_each_surface(client_surface(c), fn, data);
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c)) {
|
||||
wlr_surface_for_each_surface(c->surface.xwayland->surface,
|
||||
fn, data);
|
||||
if (client_is_x11(c))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
wlr_xdg_surface_for_each_surface(c->surface.xdg, fn, data);
|
||||
wlr_xdg_surface_for_each_popup_surface(c->surface.xdg, fn, data);
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
@ -95,6 +103,16 @@ client_is_float_type(Client *c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
client_wants_fullscreen(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return c->surface.xwayland->fullscreen;
|
||||
#endif
|
||||
return c->surface.xdg->toplevel->requested.fullscreen;
|
||||
}
|
||||
|
||||
static inline int
|
||||
client_is_unmanaged(Client *c)
|
||||
{
|
||||
@ -148,18 +166,7 @@ client_set_tiled(Client *c, uint32_t edges)
|
||||
if (client_is_x11(c))
|
||||
return;
|
||||
#endif
|
||||
wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP |
|
||||
WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
|
||||
}
|
||||
|
||||
static inline struct wlr_surface *
|
||||
client_surface(Client *c)
|
||||
{
|
||||
#ifdef XWAYLAND
|
||||
if (client_is_x11(c))
|
||||
return c->surface.xwayland->surface;
|
||||
#endif
|
||||
return c->surface.xdg->surface;
|
||||
wlr_xdg_toplevel_set_tiled(c->surface.xdg, edges);
|
||||
}
|
||||
|
||||
static inline struct wlr_surface *
|
||||
|
||||
@ -84,7 +84,7 @@ static const Key keys[] = {
|
||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
|
||||
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
@ -96,7 +96,7 @@ static const Key keys[] = {
|
||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||
TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3),
|
||||
TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4),
|
||||
TAGKEYS( XKB_KEY_6, XKB_KEY_caret, 5),
|
||||
TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5),
|
||||
TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
|
||||
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
|
||||
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
PREFIX = /usr/local
|
||||
|
||||
# Default compile flags (overridable by environment)
|
||||
CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wdeclaration-after-statement
|
||||
CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement
|
||||
|
||||
# Uncomment to build XWayland support
|
||||
#CFLAGS += -DXWAYLAND
|
||||
|
||||
206
dwl.c
206
dwl.c
@ -13,6 +13,7 @@
|
||||
#include <libinput.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
@ -57,7 +58,7 @@
|
||||
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
||||
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
|
||||
#define VISIBLEON(C, M) ((C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
|
||||
#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
|
||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define END(A) ((A) + LENGTH(A))
|
||||
#define TAGMASK ((1 << LENGTH(tags)) - 1)
|
||||
@ -102,7 +103,7 @@ typedef struct {
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener set_title;
|
||||
struct wl_listener fullscreen;
|
||||
struct wlr_box geom; /* layout-relative, includes border */
|
||||
struct wlr_box geom, prev; /* layout-relative, includes border */
|
||||
Monitor *mon;
|
||||
#ifdef XWAYLAND
|
||||
unsigned int type;
|
||||
@ -113,10 +114,6 @@ typedef struct {
|
||||
unsigned int tags;
|
||||
int isfloating, isurgent;
|
||||
uint32_t resize; /* configure serial of a pending resize */
|
||||
int prevx;
|
||||
int prevy;
|
||||
int prevwidth;
|
||||
int prevheight;
|
||||
int isfullscreen;
|
||||
} Client;
|
||||
|
||||
@ -130,11 +127,6 @@ typedef struct {
|
||||
Client *c;
|
||||
} Subsurface;
|
||||
|
||||
typedef struct {
|
||||
struct wl_listener request_mode;
|
||||
struct wl_listener destroy;
|
||||
} Decoration;
|
||||
|
||||
typedef struct {
|
||||
uint32_t mod;
|
||||
xkb_keysym_t keysym;
|
||||
@ -185,7 +177,7 @@ struct Monitor {
|
||||
struct wl_listener destroy;
|
||||
struct wlr_box m; /* monitor area, layout-relative */
|
||||
struct wlr_box w; /* window area, layout-relative */
|
||||
struct wl_list layers[4]; // LayerSurface::link
|
||||
struct wl_list layers[4]; /* LayerSurface::link */
|
||||
const Layout *lt[2];
|
||||
unsigned int seltags;
|
||||
unsigned int sellt;
|
||||
@ -326,6 +318,7 @@ static const char broken[] = "broken";
|
||||
static struct wl_display *dpy;
|
||||
static struct wlr_backend *backend;
|
||||
static struct wlr_renderer *drw;
|
||||
static struct wlr_allocator *alloc;
|
||||
static struct wlr_compositor *compositor;
|
||||
|
||||
static struct wlr_xdg_shell *xdg_shell;
|
||||
@ -423,7 +416,7 @@ applyexclusive(struct wlr_box *usable_area,
|
||||
int32_t margin_top, int32_t margin_right,
|
||||
int32_t margin_bottom, int32_t margin_left) {
|
||||
Edge edges[] = {
|
||||
{ // Top
|
||||
{ /* Top */
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
|
||||
.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
||||
@ -432,7 +425,7 @@ applyexclusive(struct wlr_box *usable_area,
|
||||
.negative_axis = &usable_area->height,
|
||||
.margin = margin_top,
|
||||
},
|
||||
{ // Bottom
|
||||
{ /* Bottom */
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
||||
.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
||||
@ -441,7 +434,7 @@ applyexclusive(struct wlr_box *usable_area,
|
||||
.negative_axis = &usable_area->height,
|
||||
.margin = margin_bottom,
|
||||
},
|
||||
{ // Left
|
||||
{ /* Left */
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT,
|
||||
.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
|
||||
@ -450,7 +443,7 @@ applyexclusive(struct wlr_box *usable_area,
|
||||
.negative_axis = &usable_area->width,
|
||||
.margin = margin_left,
|
||||
},
|
||||
{ // Right
|
||||
{ /* Right */
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
|
||||
.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
|
||||
@ -534,7 +527,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int
|
||||
|
||||
bounds = state->exclusive_zone == -1 ? full_area : *usable_area;
|
||||
|
||||
// Horizontal axis
|
||||
/* Horizontal axis */
|
||||
if ((state->anchor & both_horiz) && box.width == 0) {
|
||||
box.x = bounds.x;
|
||||
box.width = bounds.width;
|
||||
@ -545,7 +538,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int
|
||||
} else {
|
||||
box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
|
||||
}
|
||||
// Vertical axis
|
||||
/* Vertical axis */
|
||||
if ((state->anchor & both_vert) && box.height == 0) {
|
||||
box.y = bounds.y;
|
||||
box.height = bounds.height;
|
||||
@ -556,7 +549,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int
|
||||
} else {
|
||||
box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
|
||||
}
|
||||
// Margin
|
||||
/* Margin */
|
||||
if ((state->anchor & both_horiz) == both_horiz) {
|
||||
box.x += state->margin.left;
|
||||
box.width -= state->margin.left + state->margin.right;
|
||||
@ -574,7 +567,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int
|
||||
box.y -= state->margin.bottom;
|
||||
}
|
||||
if (box.width < 0 || box.height < 0) {
|
||||
wlr_layer_surface_v1_close(wlr_layer_surface);
|
||||
wlr_layer_surface_v1_destroy(wlr_layer_surface);
|
||||
continue;
|
||||
}
|
||||
layersurface->geo = box;
|
||||
@ -590,6 +583,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int
|
||||
void
|
||||
arrangelayers(Monitor *m)
|
||||
{
|
||||
int i;
|
||||
struct wlr_box usable_area = m->m;
|
||||
uint32_t layers_above_shell[] = {
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
|
||||
@ -598,38 +592,26 @@ arrangelayers(Monitor *m)
|
||||
LayerSurface *layersurface;
|
||||
struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat);
|
||||
|
||||
// Arrange exclusive surfaces from top->bottom
|
||||
arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
&usable_area, 1);
|
||||
arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
&usable_area, 1);
|
||||
arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
&usable_area, 1);
|
||||
arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
&usable_area, 1);
|
||||
/* Arrange exclusive surfaces from top->bottom */
|
||||
for (i = 3; i >= 0; i--)
|
||||
arrangelayer(m, &m->layers[i], &usable_area, 1);
|
||||
|
||||
if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) {
|
||||
m->w = usable_area;
|
||||
arrange(m);
|
||||
}
|
||||
|
||||
// Arrange non-exlusive surfaces from top->bottom
|
||||
arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
&usable_area, 0);
|
||||
arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
&usable_area, 0);
|
||||
arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
||||
&usable_area, 0);
|
||||
arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
||||
&usable_area, 0);
|
||||
/* Arrange non-exlusive surfaces from top->bottom */
|
||||
for (i = 3; i >= 0; i--)
|
||||
arrangelayer(m, &m->layers[i], &usable_area, 0);
|
||||
|
||||
// Find topmost keyboard interactive layer, if such a layer exists
|
||||
/* Find topmost keyboard interactive layer, if such a layer exists */
|
||||
for (size_t i = 0; i < LENGTH(layers_above_shell); i++) {
|
||||
wl_list_for_each_reverse(layersurface,
|
||||
&m->layers[layers_above_shell[i]], link) {
|
||||
if (layersurface->layer_surface->current.keyboard_interactive &&
|
||||
layersurface->layer_surface->mapped) {
|
||||
// Deactivate the focused client.
|
||||
/* Deactivate the focused client. */
|
||||
focusclient(NULL, 0);
|
||||
wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface,
|
||||
kb->keycodes, kb->num_keycodes, &kb->modifiers);
|
||||
@ -664,7 +646,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
wlr_idle_notify_activity(idle, seat);
|
||||
|
||||
switch (event->state) {
|
||||
case WLR_BUTTON_PRESSED:;
|
||||
case WLR_BUTTON_PRESSED:
|
||||
/* Change focus if the button was _pressed_ over a client */
|
||||
if ((c = xytoclient(cursor->x, cursor->y)))
|
||||
focusclient(c, 1);
|
||||
@ -683,8 +665,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||
/* TODO should reset to the pointer focus's current setcursor */
|
||||
if (cursor_mode != CurNormal) {
|
||||
wlr_xcursor_manager_set_cursor_image(cursor_mgr,
|
||||
"left_ptr", cursor);
|
||||
wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor);
|
||||
cursor_mode = CurNormal;
|
||||
/* Drop the window off on its new monitor */
|
||||
selmon = xytomon(cursor->x, cursor->y);
|
||||
@ -746,10 +727,11 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
wl_list_remove(&m->link);
|
||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||
|
||||
nmons = wl_list_length(&mons);
|
||||
do // don't switch to disabled mons
|
||||
selmon = wl_container_of(mons.prev, selmon, link);
|
||||
while (!selmon->wlr_output->enabled && i++ < nmons);
|
||||
if ((nmons = wl_list_length(&mons)))
|
||||
do /* don't switch to disabled mons */
|
||||
selmon = wl_container_of(mons.prev, selmon, link);
|
||||
while (!selmon->wlr_output->enabled && i++ < nmons);
|
||||
|
||||
focusclient(focustop(selmon), 1);
|
||||
closemon(m);
|
||||
free(m);
|
||||
@ -758,7 +740,7 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
void
|
||||
closemon(Monitor *m)
|
||||
{
|
||||
// move closed monitor's clients to the focused one
|
||||
/* move closed monitor's clients to the focused one */
|
||||
Client *c;
|
||||
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
@ -801,7 +783,7 @@ commitnotify(struct wl_listener *listener, void *data)
|
||||
Client *c = wl_container_of(listener, c, commit);
|
||||
|
||||
/* mark a pending resize as completed */
|
||||
if (c->resize && c->resize <= c->surface.xdg->configure_serial)
|
||||
if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
|
||||
c->resize = 0;
|
||||
|
||||
// Damage the whole screen
|
||||
@ -823,6 +805,8 @@ createkeyboard(struct wlr_input_device *device)
|
||||
struct xkb_context *context;
|
||||
struct xkb_keymap *keymap;
|
||||
Keyboard *kb = device->data = calloc(1, sizeof(*kb));
|
||||
if (!kb)
|
||||
EBARF("createkeyboard: calloc");
|
||||
kb->device = device;
|
||||
|
||||
/* Prepare an XKB keymap and assign it to the keyboard. */
|
||||
@ -854,8 +838,12 @@ createmon(struct wl_listener *listener, void *data)
|
||||
struct wlr_output *wlr_output = data;
|
||||
const MonitorRule *r;
|
||||
Monitor *m = wlr_output->data = calloc(1, sizeof(*m));
|
||||
if (!m)
|
||||
EBARF("createmon: calloc");
|
||||
m->wlr_output = wlr_output;
|
||||
|
||||
wlr_output_init_render(wlr_output, alloc, drw);
|
||||
|
||||
/* Initialize monitor state using configured rules */
|
||||
for (size_t i = 0; i < LENGTH(m->layers); i++)
|
||||
wl_list_init(&m->layers[i]);
|
||||
@ -900,6 +888,16 @@ createmon(struct wl_listener *listener, void *data)
|
||||
wlr_output_layout_add(output_layout, wlr_output, r->x, r->y);
|
||||
sgeom = *wlr_output_layout_get_box(output_layout, NULL);
|
||||
|
||||
/* If length == 1 we need update selmon.
|
||||
* Maybe it will change in run(). */
|
||||
if (wl_list_length(&mons) == 1) {
|
||||
Client *c;
|
||||
selmon = m;
|
||||
/* If there is any client, set c->mon to this monitor */
|
||||
wl_list_for_each(c, &clients, link)
|
||||
setmon(c, m, c->tags);
|
||||
}
|
||||
|
||||
/* When adding monitors, the geometries of all monitors must be updated */
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
/* The first monitor in the list is the most recently added */
|
||||
@ -926,6 +924,8 @@ createnotify(struct wl_listener *listener, void *data)
|
||||
|
||||
/* Allocate a Client for this surface */
|
||||
c = xdg_surface->data = calloc(1, sizeof(*c));
|
||||
if (!c)
|
||||
EBARF("createnotify: calloc");
|
||||
c->surface.xdg = xdg_surface;
|
||||
c->bw = borderpx;
|
||||
|
||||
@ -952,6 +952,8 @@ createlayersurface(struct wl_listener *listener, void *data)
|
||||
}
|
||||
|
||||
layersurface = calloc(1, sizeof(LayerSurface));
|
||||
if (!layersurface)
|
||||
EBARF("layersurface: calloc");
|
||||
LISTEN(&wlr_layer_surface->surface->events.commit,
|
||||
&layersurface->surface_commit, commitlayersurfacenotify);
|
||||
LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy,
|
||||
@ -965,13 +967,14 @@ createlayersurface(struct wl_listener *listener, void *data)
|
||||
wlr_layer_surface->data = layersurface;
|
||||
|
||||
m = wlr_layer_surface->output->data;
|
||||
wl_list_insert(&m->layers[wlr_layer_surface->client_pending.layer],
|
||||
wl_list_insert(&m->layers[wlr_layer_surface->pending.layer],
|
||||
&layersurface->link);
|
||||
|
||||
// Temporarily set the layer's current state to client_pending
|
||||
// so that we can easily arrange it
|
||||
/* Temporarily set the layer's current state to pending
|
||||
* so that we can easily arrange it
|
||||
*/
|
||||
old_state = wlr_layer_surface->current;
|
||||
wlr_layer_surface->current = wlr_layer_surface->client_pending;
|
||||
wlr_layer_surface->current = wlr_layer_surface->pending;
|
||||
arrangelayers(m);
|
||||
wlr_layer_surface->current = old_state;
|
||||
}
|
||||
@ -1084,28 +1087,33 @@ void
|
||||
setfullscreen(Client *c, int fullscreen)
|
||||
{
|
||||
c->isfullscreen = fullscreen;
|
||||
c->bw = (1 - fullscreen) * borderpx;
|
||||
c->bw = fullscreen ? 0 : borderpx;
|
||||
client_set_fullscreen(c, fullscreen);
|
||||
|
||||
if (fullscreen) {
|
||||
c->prevx = c->geom.x;
|
||||
c->prevy = c->geom.y;
|
||||
c->prevheight = c->geom.height;
|
||||
c->prevwidth = c->geom.width;
|
||||
c->prev = c->geom;
|
||||
resize(c, c->mon->m.x, c->mon->m.y, c->mon->m.width, c->mon->m.height, 0);
|
||||
} else {
|
||||
/* restore previous size instead of arrange for floating windows since
|
||||
* client positions are set by the user and cannot be recalculated */
|
||||
resize(c, c->prevx, c->prevy, c->prevwidth, c->prevheight, 0);
|
||||
arrange(c->mon);
|
||||
resize(c, c->prev.x, c->prev.y, c->prev.width, c->prev.height, 0);
|
||||
}
|
||||
arrange(c->mon);
|
||||
printstatus();
|
||||
}
|
||||
|
||||
void
|
||||
fullscreennotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
Client *c = wl_container_of(listener, c, fullscreen);
|
||||
setfullscreen(c, !c->isfullscreen);
|
||||
int fullscreen = client_wants_fullscreen(c);
|
||||
|
||||
if (!c->mon) {
|
||||
/* if the client is not mapped yet, let mapnotify() call setfullscreen() */
|
||||
c->isfullscreen = fullscreen;
|
||||
return;
|
||||
}
|
||||
setfullscreen(c, fullscreen);
|
||||
}
|
||||
|
||||
Monitor *
|
||||
@ -1340,16 +1348,16 @@ void
|
||||
killclient(const Arg *arg)
|
||||
{
|
||||
Client *sel = selclient();
|
||||
if (!sel)
|
||||
return;
|
||||
client_send_close(sel);
|
||||
if (sel)
|
||||
client_send_close(sel);
|
||||
}
|
||||
|
||||
void
|
||||
maplayersurfacenotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
LayerSurface *layersurface = wl_container_of(listener, layersurface, map);
|
||||
wlr_surface_send_enter(layersurface->layer_surface->surface, layersurface->layer_surface->output);
|
||||
wlr_surface_send_enter(layersurface->layer_surface->surface,
|
||||
layersurface->layer_surface->output);
|
||||
motionnotify(0);
|
||||
}
|
||||
|
||||
@ -1383,6 +1391,10 @@ mapnotify(struct wl_listener *listener, void *data)
|
||||
else
|
||||
#endif
|
||||
LISTEN(&c->surface.xdg->surface->events.commit, &c->commit, commitnotify);
|
||||
printstatus();
|
||||
|
||||
if (c->isfullscreen)
|
||||
setfullscreen(c, 1);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1428,7 +1440,7 @@ motionnotify(uint32_t time)
|
||||
struct wlr_surface *surface = NULL;
|
||||
Client *c = NULL;
|
||||
|
||||
// time is 0 in internal calls meant to restore pointer focus.
|
||||
/* time is 0 in internal calls meant to restore pointer focus. */
|
||||
if (time) {
|
||||
wlr_idle_notify_activity(idle, seat);
|
||||
|
||||
@ -1481,8 +1493,7 @@ motionnotify(uint32_t time)
|
||||
* default. This is what makes the cursor image appear when you move it
|
||||
* off of a client or over its border. */
|
||||
if (!surface && time)
|
||||
wlr_xcursor_manager_set_cursor_image(cursor_mgr,
|
||||
"left_ptr", cursor);
|
||||
wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor);
|
||||
|
||||
pointerfocus(c, surface, sx, sy, time);
|
||||
}
|
||||
@ -1498,8 +1509,7 @@ motionrelative(struct wl_listener *listener, void *data)
|
||||
* special configuration applied for the specific input device which
|
||||
* generated the event. You can pass NULL for the device if you want to move
|
||||
* the cursor around without any input. */
|
||||
wlr_cursor_move(cursor, event->device,
|
||||
event->delta_x, event->delta_y);
|
||||
wlr_cursor_move(cursor, event->device, event->delta_x, event->delta_y);
|
||||
motionnotify(event->time_msec);
|
||||
}
|
||||
|
||||
@ -1659,10 +1669,14 @@ printstatus(void)
|
||||
urg |= c->tags;
|
||||
}
|
||||
if ((c = focustop(m))) {
|
||||
printf("%s title %s\n", m->wlr_output->name, client_get_title(focustop(m)));
|
||||
printf("%s title %s\n", m->wlr_output->name, client_get_title(c));
|
||||
printf("%s fullscreen %u\n", m->wlr_output->name, c->isfullscreen);
|
||||
printf("%s floating %u\n", m->wlr_output->name, c->isfloating);
|
||||
sel = c->tags;
|
||||
} else {
|
||||
printf("%s title \n", m->wlr_output->name);
|
||||
printf("%s fullscreen \n", m->wlr_output->name);
|
||||
printf("%s floating \n", m->wlr_output->name);
|
||||
sel = 0;
|
||||
}
|
||||
|
||||
@ -1732,8 +1746,7 @@ render(struct wlr_surface *surface, int sx, int sy, void *data)
|
||||
* compositor.
|
||||
*/
|
||||
transform = wlr_output_transform_invert(surface->current.transform);
|
||||
wlr_matrix_project_box(matrix, &obox, transform, 0,
|
||||
output->transform_matrix);
|
||||
wlr_matrix_project_box(matrix, &obox, transform, 0, output->transform_matrix);
|
||||
|
||||
/* This takes our matrix, the texture, and an alpha, and performs the actual
|
||||
* rendering on the GPU. */
|
||||
@ -1766,8 +1779,7 @@ renderclients(Monitor *m, struct timespec *now)
|
||||
|
||||
surface = client_surface(c);
|
||||
ox = c->geom.x, oy = c->geom.y;
|
||||
wlr_output_layout_output_coords(output_layout, m->wlr_output,
|
||||
&ox, &oy);
|
||||
wlr_output_layout_output_coords(output_layout, m->wlr_output, &ox, &oy);
|
||||
|
||||
if (c->bw) {
|
||||
w = surface->current.width;
|
||||
@ -1783,8 +1795,7 @@ renderclients(Monitor *m, struct timespec *now)
|
||||
color = (c == sel) ? focuscolor : bordercolor;
|
||||
for (i = 0; i < 4; i++) {
|
||||
scalebox(&borders[i], m->wlr_output->scale);
|
||||
wlr_render_rect(drw, &borders[i], color,
|
||||
m->wlr_output->transform_matrix);
|
||||
wlr_render_rect(drw, &borders[i], color, m->wlr_output->transform_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1917,11 +1928,13 @@ run(char *startup_cmd)
|
||||
EBARF("startup: fork");
|
||||
if (startup_pid == 0) {
|
||||
dup2(piperw[0], STDIN_FILENO);
|
||||
close(piperw[0]);
|
||||
close(piperw[1]);
|
||||
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
|
||||
EBARF("startup: execl");
|
||||
}
|
||||
dup2(piperw[1], STDOUT_FILENO);
|
||||
close(piperw[1]);
|
||||
close(piperw[0]);
|
||||
}
|
||||
/* If nobody is reading the status output, don't terminate */
|
||||
@ -1998,6 +2011,7 @@ setfloating(Client *c, int floating)
|
||||
{
|
||||
c->isfloating = floating;
|
||||
arrange(c->mon);
|
||||
printstatus();
|
||||
}
|
||||
|
||||
void
|
||||
@ -2096,12 +2110,15 @@ setup(void)
|
||||
if (!(backend = wlr_backend_autocreate(dpy)))
|
||||
BARF("couldn't create backend");
|
||||
|
||||
/* If we don't provide a renderer, autocreate makes a GLES2 renderer for us.
|
||||
* The renderer is responsible for defining the various pixel formats it
|
||||
* supports for shared memory, this configures that for clients. */
|
||||
drw = wlr_backend_get_renderer(backend);
|
||||
/* Create a renderer with the default implementation */
|
||||
if (!(drw = wlr_renderer_autocreate(backend)))
|
||||
BARF("couldn't create renderer");
|
||||
wlr_renderer_init_wl_display(drw, dpy);
|
||||
|
||||
/* Create a default allocator */
|
||||
if (!(alloc = wlr_allocator_autocreate(backend, drw)))
|
||||
BARF("couldn't create allocator");
|
||||
|
||||
/* This creates some hands-off wlroots interfaces. The compositor is
|
||||
* necessary for clients to allocate surfaces and the data device manager
|
||||
* handles the clipboard. Each of these wlroots interfaces has room for you
|
||||
@ -2201,12 +2218,9 @@ setup(void)
|
||||
wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,
|
||||
&new_virtual_keyboard);
|
||||
seat = wlr_seat_create(dpy, "seat0");
|
||||
wl_signal_add(&seat->events.request_set_cursor,
|
||||
&request_cursor);
|
||||
wl_signal_add(&seat->events.request_set_selection,
|
||||
&request_set_sel);
|
||||
wl_signal_add(&seat->events.request_set_primary_selection,
|
||||
&request_set_psel);
|
||||
wl_signal_add(&seat->events.request_set_cursor, &request_cursor);
|
||||
wl_signal_add(&seat->events.request_set_selection, &request_set_sel);
|
||||
wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel);
|
||||
|
||||
output_mgr = wlr_output_manager_v1_create(dpy);
|
||||
wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
|
||||
@ -2284,7 +2298,7 @@ tile(Monitor *m)
|
||||
Client *c;
|
||||
|
||||
wl_list_for_each(c, &clients, link)
|
||||
if (VISIBLEON(c, m) && !c->isfloating)
|
||||
if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
|
||||
n++;
|
||||
if (n == 0)
|
||||
return;
|
||||
@ -2314,10 +2328,9 @@ void
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
Client *sel = selclient();
|
||||
if (!sel)
|
||||
return;
|
||||
/* return if fullscreen */
|
||||
setfloating(sel, !sel->isfloating /* || sel->isfixed */);
|
||||
if (sel && !sel->isfullscreen)
|
||||
setfloating(sel, !sel->isfloating);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2371,11 +2384,14 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the surface is unmapped, and should no longer be shown. */
|
||||
Client *c = wl_container_of(listener, c, unmap);
|
||||
|
||||
// Damage the whole screen
|
||||
if (c->mon)
|
||||
wlr_output_damage_add_whole(c->mon->damage);
|
||||
|
||||
if (c == grabc) {
|
||||
cursor_mode = CurNormal;
|
||||
grabc = NULL;
|
||||
}
|
||||
wl_list_remove(&c->link);
|
||||
if (client_is_unmanaged(c))
|
||||
return;
|
||||
@ -2383,6 +2399,7 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||
setmon(c, NULL, 0);
|
||||
wl_list_remove(&c->flink);
|
||||
wl_list_remove(&c->slink);
|
||||
printstatus();
|
||||
}
|
||||
|
||||
void
|
||||
@ -2576,6 +2593,8 @@ createnotifyx11(struct wl_listener *listener, void *data)
|
||||
|
||||
/* Allocate a Client for this surface */
|
||||
c = xwayland_surface->data = calloc(1, sizeof(*c));
|
||||
if (!c)
|
||||
EBARF("createnotifyx11: calloc");
|
||||
c->surface.xwayland = xwayland_surface;
|
||||
c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed;
|
||||
c->bw = borderpx;
|
||||
@ -2727,8 +2746,7 @@ main(int argc, char *argv[])
|
||||
if (optind < argc)
|
||||
goto usage;
|
||||
|
||||
// Wayland requires XDG_RUNTIME_DIR for creating its communications
|
||||
// socket
|
||||
/* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */
|
||||
if (!getenv("XDG_RUNTIME_DIR"))
|
||||
BARF("XDG_RUNTIME_DIR must be set");
|
||||
setup();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user