summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--client.h176
-rw-r--r--dwl.c425
3 files changed, 338 insertions, 270 deletions
diff --git a/Makefile b/Makefile
index 5320e42..6cde460 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ include config.mk
# flags for compiling
DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND)
-DWLDEVCFLAGS = -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\
+DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\
-Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types
# CFLAGS / LDFLAGS
@@ -16,7 +16,7 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS)
all: dwl
dwl: dwl.o util.o
$(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@
-dwl.o: dwl.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h
+dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h
util.o: util.c util.h
# wayland-scanner is a tool which generates C headers and rigging for Wayland
@@ -31,6 +31,9 @@ xdg-shell-protocol.h:
wlr-layer-shell-unstable-v1-protocol.h:
$(WAYLAND_SCANNER) server-header \
protocols/wlr-layer-shell-unstable-v1.xml $@
+cursor-shape-v1-protocol.h:
+ $(WAYLAND_SCANNER) server-header \
+ $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@
config.h:
cp config.def.h $@
diff --git a/client.h b/client.h
index cf1ed85..71c7d76 100644
--- a/client.h
+++ b/client.h
@@ -11,34 +11,8 @@ client_is_x11(Client *c)
{
#ifdef XWAYLAND
return c->type == X11Managed || c->type == X11Unmanaged;
-#else
- return 0;
#endif
-}
-
-static inline void
-client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min)
-{
- struct wlr_xdg_toplevel *toplevel;
- struct wlr_xdg_toplevel_state *state;
-#ifdef XWAYLAND
- if (client_is_x11(c)) {
- xcb_size_hints_t *size_hints = c->surface.xwayland->size_hints;
- if (size_hints) {
- max->width = size_hints->max_width;
- max->height = size_hints->max_height;
- min->width = size_hints->min_width;
- min->height = size_hints->min_height;
- }
- return;
- }
-#endif
- toplevel = c->surface.xdg->toplevel;
- state = &toplevel->current;
- max->width = state->max_width;
- max->height = state->max_height;
- min->width = state->min_width;
- min->height = state->min_height;
+ return 0;
}
static inline struct wlr_surface *
@@ -54,7 +28,7 @@ client_surface(Client *c)
static inline int
toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
{
- struct wlr_xdg_surface *xdg_surface;
+ struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
struct wlr_surface *root_surface;
struct wlr_layer_surface_v1 *layer_surface;
Client *c = NULL;
@@ -65,44 +39,44 @@ toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
#endif
if (!s)
- return type;
+ return -1;
root_surface = wlr_surface_get_root_surface(s);
#ifdef XWAYLAND
- if (wlr_surface_is_xwayland_surface(root_surface)
- && (xsurface = wlr_xwayland_surface_from_wlr_surface(root_surface))) {
+ if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
c = xsurface->data;
type = c->type;
goto end;
}
#endif
- if (wlr_surface_is_layer_surface(root_surface)
- && (layer_surface = wlr_layer_surface_v1_from_wlr_surface(root_surface))) {
+ if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
l = layer_surface->data;
type = LayerShell;
goto end;
}
- if (wlr_surface_is_xdg_surface(root_surface)
- && (xdg_surface = wlr_xdg_surface_from_wlr_surface(root_surface))) {
- while (1) {
- switch (xdg_surface->role) {
- case WLR_XDG_SURFACE_ROLE_POPUP:
- if (!xdg_surface->popup->parent)
- return -1;
- else if (!wlr_surface_is_xdg_surface(xdg_surface->popup->parent))
- return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl);
-
- xdg_surface = wlr_xdg_surface_from_wlr_surface(xdg_surface->popup->parent);
- break;
- case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
- c = xdg_surface->data;
- type = c->type;
- goto end;
- case WLR_XDG_SURFACE_ROLE_NONE:
+ xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
+ while (xdg_surface) {
+ tmp_xdg_surface = NULL;
+ switch (xdg_surface->role) {
+ case WLR_XDG_SURFACE_ROLE_POPUP:
+ if (!xdg_surface->popup || !xdg_surface->popup->parent)
return -1;
- }
+
+ tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
+
+ if (!tmp_xdg_surface)
+ return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl);
+
+ xdg_surface = tmp_xdg_surface;
+ break;
+ case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
+ c = xdg_surface->data;
+ type = c->type;
+ goto end;
+ case WLR_XDG_SURFACE_ROLE_NONE:
+ return -1;
}
}
@@ -118,19 +92,16 @@ end:
static inline void
client_activate_surface(struct wlr_surface *s, int activated)
{
- struct wlr_xdg_surface *surface;
+ struct wlr_xdg_toplevel *toplevel;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xsurface;
- if (wlr_surface_is_xwayland_surface(s)
- && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) {
+ if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
wlr_xwayland_surface_activate(xsurface, activated);
return;
}
#endif
- if (wlr_surface_is_xdg_surface(s)
- && (surface = wlr_xdg_surface_from_wlr_surface(s))
- && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL)
- wlr_xdg_toplevel_set_activated(surface->toplevel, activated);
+ if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
+ wlr_xdg_toplevel_set_activated(toplevel, activated);
}
static inline uint32_t
@@ -140,31 +111,45 @@ client_set_bounds(Client *c, int32_t width, int32_t height)
if (client_is_x11(c))
return 0;
#endif
- if (c->surface.xdg->client->shell->version >=
- XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0)
+ if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
+ XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0
+ && (c->bounds.width != width || c->bounds.height != height)) {
+ c->bounds.width = width;
+ c->bounds.height = height;
return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height);
+ }
return 0;
}
-static inline void
-client_for_each_surface(Client *c, wlr_surface_iterator_func_t fn, void *data)
+static inline const char *
+client_get_appid(Client *c)
{
- wlr_surface_for_each_surface(client_surface(c), fn, data);
#ifdef XWAYLAND
if (client_is_x11(c))
- return;
+ return c->surface.xwayland->class;
#endif
- wlr_xdg_surface_for_each_popup_surface(c->surface.xdg, fn, data);
+ return c->surface.xdg->toplevel->app_id;
}
-static inline const char *
-client_get_appid(Client *c)
+static inline void
+client_get_clip(Client *c, struct wlr_box *clip)
{
+ struct wlr_box xdg_geom = {0};
+ *clip = (struct wlr_box){
+ .x = 0,
+ .y = 0,
+ .width = c->geom.width - c->bw,
+ .height = c->geom.height - c->bw,
+ };
+
#ifdef XWAYLAND
if (client_is_x11(c))
- return c->surface.xwayland->class;
+ return;
#endif
- return c->surface.xdg->toplevel->app_id;
+
+ wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom);
+ clip->x = xdg_geom.x;
+ clip->y = xdg_geom.y;
}
static inline void
@@ -192,7 +177,6 @@ client_get_parent(Client *c)
#endif
if (c->surface.xdg->toplevel->parent)
toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
-
return p;
}
@@ -209,35 +193,35 @@ client_get_title(Client *c)
static inline int
client_is_float_type(Client *c)
{
- struct wlr_box min = {0}, max = {0};
- client_get_size_hints(c, &max, &min);
+ struct wlr_xdg_toplevel *toplevel;
+ struct wlr_xdg_toplevel_state state;
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
+ xcb_size_hints_t *size_hints = surface->size_hints;
+ size_t i;
if (surface->modal)
return 1;
- for (size_t i = 0; i < surface->window_type_len; i++)
+ for (i = 0; i < surface->window_type_len; i++)
if (surface->window_type[i] == netatom[NetWMWindowTypeDialog]
|| surface->window_type[i] == netatom[NetWMWindowTypeSplash]
|| surface->window_type[i] == netatom[NetWMWindowTypeToolbar]
|| surface->window_type[i] == netatom[NetWMWindowTypeUtility])
return 1;
+
+ return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
+ && (size_hints->max_width == size_hints->min_width
+ || size_hints->max_height == size_hints->min_height);
}
#endif
- return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0)
- && (min.width == max.width || min.height == max.height));
-}
-static inline int
-client_is_mapped(Client *c)
-{
-#ifdef XWAYLAND
- if (client_is_x11(c))
- return c->surface.xwayland->mapped;
-#endif
- return c->surface.xdg->mapped;
+ toplevel = c->surface.xdg->toplevel;
+ state = toplevel->current;
+ return toplevel->parent || (state.min_width != 0 && state.min_height != 0
+ && (state.min_width == state.max_width
+ || state.min_height == state.max_height));
}
static inline int
@@ -247,7 +231,8 @@ client_is_rendered_on_mon(Client *c, Monitor *m)
* but rather actual displaying of the pixels.
* Usually VISIBLEON suffices and is also faster. */
struct wlr_surface_output *s;
- if (!c->scene->node.enabled)
+ int unused_lx, unused_ly;
+ if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
return 0;
wl_list_for_each(s, &client_surface(c)->current_outputs, link)
if (s->output == m->wlr_output)
@@ -366,18 +351,25 @@ client_set_tiled(Client *c, uint32_t edges)
if (client_is_x11(c))
return;
#endif
- wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
+ if (wl_resource_get_version(c->surface.xdg->resource)
+ >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
+ wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
+ } else {
+ wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE);
+ }
}
-static inline struct wlr_surface *
-client_surface_at(Client *c, double cx, double cy, double *sx, double *sy)
+static inline void
+client_set_suspended(Client *c, int suspended)
{
#ifdef XWAYLAND
- if (client_is_x11(c))
- return wlr_surface_surface_at(c->surface.xwayland->surface,
- cx, cy, sx, sy);
+ if (client_is_x11(c)) {
+ wlr_xwayland_surface_set_withdrawn(c->surface.xwayland, suspended);
+ return;
+ }
#endif
- return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy);
+
+ wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
}
static inline int
diff --git a/dwl.c b/dwl.c
index b78ed02..ef27a1d 100644
--- a/dwl.c
+++ b/dwl.c
@@ -3,7 +3,6 @@
*/
#include <getopt.h>
#include <libinput.h>
-#include <limits.h>
#include <linux/input-event-codes.h>
#include <signal.h>
#include <stdio.h>
@@ -18,15 +17,17 @@
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_cursor.h>
+#include <wlr/types/wlr_cursor_shape_v1.h>
#include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_drm.h>
+#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_export_dmabuf_v1.h>
+#include <wlr/types/wlr_fractional_scale_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
-#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_input_device.h>
-#include <wlr/types/wlr_input_inhibitor.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output.h>
@@ -69,7 +70,7 @@
#define END(A) ((A) + LENGTH(A))
#define TAGMASK ((1u << TAGCOUNT) - 1)
#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
-#define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat)
+#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
/* enums */
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
@@ -117,8 +118,11 @@ typedef struct {
struct wl_listener set_title;
struct wl_listener fullscreen;
struct wlr_box prev; /* layout-relative, includes border */
+ struct wlr_box bounds;
#ifdef XWAYLAND
struct wl_listener activate;
+ struct wl_listener associate;
+ struct wl_listener dissociate;
struct wl_listener configure;
struct wl_listener set_hints;
#endif
@@ -179,6 +183,7 @@ struct Monitor {
struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
struct wl_listener frame;
struct wl_listener destroy;
+ struct wl_listener request_state;
struct wl_listener destroy_lock_surface;
struct wlr_session_lock_surface_v1 *lock_surface;
struct wlr_box m; /* monitor area, layout-relative */
@@ -189,6 +194,7 @@ struct Monitor {
unsigned int sellt;
uint32_t tagset[2];
double mfact;
+ int gamma_lut_changed;
int nmaster;
char ltsymbol[16];
};
@@ -286,11 +292,14 @@ static void printstatus(void);
static void quit(const Arg *arg);
static void rendermon(struct wl_listener *listener, void *data);
static void requeststartdrag(struct wl_listener *listener, void *data);
+static void requestmonstate(struct wl_listener *listener, void *data);
static void resize(Client *c, struct wlr_box geo, int interact);
static void run(char *startup_cmd);
static void setcursor(struct wl_listener *listener, void *data);
+static void setcursorshape(struct wl_listener *listener, void *data);
static void setfloating(Client *c, int floating);
static void setfullscreen(Client *c, int fullscreen);
+static void setgamma(struct wl_listener *listener, void *data);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setmon(Client *c, Monitor *m, uint32_t newtags);
@@ -321,7 +330,6 @@ static void zoom(const Arg *arg);
/* variables */
static const char broken[] = "broken";
-static const char *cursor_image = "left_ptr";
static pid_t child_pid = -1;
static int locked;
static void *exclusive_focus;
@@ -335,19 +343,20 @@ static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay };
static struct wlr_renderer *drw;
static struct wlr_allocator *alloc;
static struct wlr_compositor *compositor;
+static struct wlr_session *session;
static struct wlr_xdg_shell *xdg_shell;
static struct wlr_xdg_activation_v1 *activation;
static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr;
static struct wl_list clients; /* tiling order */
static struct wl_list fstack; /* focus order */
-static struct wlr_idle *idle;
static struct wlr_idle_notifier_v1 *idle_notifier;
static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr;
-static struct wlr_input_inhibit_manager *input_inhibit_mgr;
static struct wlr_layer_shell_v1 *layer_shell;
static struct wlr_output_manager_v1 *output_mgr;
+static struct wlr_gamma_control_manager_v1 *gamma_control_mgr;
static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
+static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr;
static struct wlr_cursor *cursor;
static struct wlr_xcursor_manager *cursor_mgr;
@@ -355,6 +364,7 @@ static struct wlr_xcursor_manager *cursor_mgr;
static struct wlr_session_lock_manager_v1 *session_lock_mgr;
static struct wlr_scene_rect *locked_bg;
static struct wlr_session_lock_v1 *cur_lock;
+static struct wl_listener lock_listener = {.notify = locksession};
static struct wlr_seat *seat;
static struct wl_list keyboards;
@@ -367,42 +377,15 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
-/* global event handlers */
-static struct wl_listener cursor_axis = {.notify = axisnotify};
-static struct wl_listener cursor_button = {.notify = buttonpress};
-static struct wl_listener cursor_frame = {.notify = cursorframe};
-static struct wl_listener cursor_motion = {.notify = motionrelative};
-static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute};
-static struct wl_listener drag_icon_destroy = {.notify = destroydragicon};
-static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor};
-static struct wl_listener idle_inhibitor_destroy = {.notify = destroyidleinhibitor};
-static struct wl_listener layout_change = {.notify = updatemons};
-static struct wl_listener new_input = {.notify = inputdevice};
-static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard};
-static struct wl_listener new_output = {.notify = createmon};
-static struct wl_listener new_xdg_surface = {.notify = createnotify};
-static struct wl_listener new_xdg_decoration = {.notify = createdecoration};
-static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface};
-static struct wl_listener output_mgr_apply = {.notify = outputmgrapply};
-static struct wl_listener output_mgr_test = {.notify = outputmgrtest};
-static struct wl_listener request_activate = {.notify = urgent};
-static struct wl_listener request_cursor = {.notify = setcursor};
-static struct wl_listener request_set_psel = {.notify = setpsel};
-static struct wl_listener request_set_sel = {.notify = setsel};
-static struct wl_listener request_start_drag = {.notify = requeststartdrag};
-static struct wl_listener start_drag = {.notify = startdrag};
-static struct wl_listener session_lock_create_lock = {.notify = locksession};
-static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmgr};
-
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
+static void associatex11(struct wl_listener *listener, void *data);
static void configurex11(struct wl_listener *listener, void *data);
static void createnotifyx11(struct wl_listener *listener, void *data);
+static void dissociatex11(struct wl_listener *listener, void *data);
static xcb_atom_t getatom(xcb_connection_t *xc, const char *name);
static void sethints(struct wl_listener *listener, void *data);
static void xwaylandready(struct wl_listener *listener, void *data);
-static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};
-static struct wl_listener xwayland_ready = {.notify = xwaylandready};
static struct wlr_xwayland *xwayland;
static xcb_atom_t netatom[NetLast];
#endif
@@ -417,19 +400,9 @@ static xcb_atom_t netatom[NetLast];
void
applybounds(Client *c, struct wlr_box *bbox)
{
- if (!c->isfullscreen) {
- struct wlr_box min = {0}, max = {0};
- client_get_size_hints(c, &max, &min);
- /* try to set size hints */
- c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width);
- c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height);
- /* Some clients set their max size to INT_MAX, which does not violate the
- * protocol but it's unnecesary, as they can set their max size to zero. */
- if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */
- c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width);
- if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */
- c->geom.height = MIN(max.height + (2 * c->bw), c->geom.height);
- }
+ /* set minimum possible */
+ c->geom.width = MAX(1, c->geom.width);
+ c->geom.height = MAX(1, c->geom.height);
if (c->geom.x >= bbox->x + bbox->width)
c->geom.x = bbox->x + bbox->width - c->geom.width;
@@ -475,9 +448,12 @@ void
arrange(Monitor *m)
{
Client *c;
- wl_list_for_each(c, &clients, link)
- if (c->mon == m)
+ wl_list_for_each(c, &clients, link) {
+ if (c->mon == m) {
wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m));
+ client_set_suspended(c, !VISIBLEON(c, m));
+ }
+ }
wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
(c = focustop(m)) && c->isfullscreen);
@@ -559,7 +535,7 @@ axisnotify(struct wl_listener *listener, void *data)
/* This event is forwarded by the cursor when a pointer emits an axis event,
* for example when you move the scroll wheel. */
struct wlr_pointer_axis_event *event = data;
- IDLE_NOTIFY_ACTIVITY;
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
/* TODO: allow usage of scroll whell for mousebindings, it can be implemented
* checking the event's orientation and the delta of the event */
/* Notify the client with pointer focus of the axis event. */
@@ -577,7 +553,7 @@ buttonpress(struct wl_listener *listener, void *data)
Client *c;
const Button *b;
- IDLE_NOTIFY_ACTIVITY;
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
switch (event->state) {
case WLR_BUTTON_PRESSED:
@@ -602,13 +578,10 @@ buttonpress(struct wl_listener *listener, void *data)
break;
case WLR_BUTTON_RELEASED:
/* If you released any buttons, we exit interactive move/resize mode. */
+ /* TODO should reset to the pointer focus's current setcursor */
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
cursor_mode = CurNormal;
- /* Clear the pointer focus, this way if the cursor is over a surface
- * we will send an enter event after which the client will provide us
- * a cursor surface */
- wlr_seat_pointer_clear_focus(seat);
- motionnotify(0);
/* Drop the window off on its new monitor */
selmon = xytomon(cursor->x, cursor->y);
setmon(grabc, selmon, 0);
@@ -627,7 +600,7 @@ buttonpress(struct wl_listener *listener, void *data)
void
chvt(const Arg *arg)
{
- wlr_session_change_vt(wlr_backend_get_session(backend), arg->ui);
+ wlr_session_change_vt(session, arg->ui);
}
void
@@ -645,7 +618,6 @@ checkidleinhibitor(struct wlr_surface *exclude)
}
}
- wlr_idle_set_enabled(idle, NULL, !inhibited);
wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited);
}
@@ -654,21 +626,19 @@ cleanup(void)
{
#ifdef XWAYLAND
wlr_xwayland_destroy(xwayland);
+ xwayland = NULL;
#endif
wl_display_destroy_clients(dpy);
if (child_pid > 0) {
kill(child_pid, SIGTERM);
waitpid(child_pid, NULL, 0);
}
- wlr_backend_destroy(backend);
- wlr_scene_node_destroy(&scene->tree.node);
- wlr_renderer_destroy(drw);
- wlr_allocator_destroy(alloc);
wlr_xcursor_manager_destroy(cursor_mgr);
- wlr_cursor_destroy(cursor);
wlr_output_layout_destroy(output_layout);
- wlr_seat_destroy(seat);
wl_display_destroy(dpy);
+ /* Destroy after the wayland display (when the monitors are already destroyed)
+ to avoid destroying them with an invalid scene output. */
+ wlr_scene_node_destroy(&scene->tree.node);
}
void
@@ -757,9 +727,9 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data)
wlr_scene_node_reparent(&layersurface->popups->node, layers[LyrTop]);
if (wlr_layer_surface->current.committed == 0
- && layersurface->mapped == wlr_layer_surface->mapped)
+ && layersurface->mapped == wlr_layer_surface->surface->mapped)
return;
- layersurface->mapped = wlr_layer_surface->mapped;
+ layersurface->mapped = wlr_layer_surface->surface->mapped;
arrangelayers(layersurface->mon);
}
@@ -769,6 +739,9 @@ commitnotify(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, commit);
+ if (client_surface(c)->mapped)
+ resize(c, c->geom, (c->isfloating && !c->isfullscreen));
+
/* mark a pending resize as completed */
if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
c->resize = 0;
@@ -785,7 +758,7 @@ void
createidleinhibitor(struct wl_listener *listener, void *data)
{
struct wlr_idle_inhibitor_v1 *idle_inhibitor = data;
- wl_signal_add(&idle_inhibitor->events.destroy, &idle_inhibitor_destroy);
+ LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor);
checkidleinhibitor(NULL);
}
@@ -840,21 +813,19 @@ createlayersurface(struct wl_listener *listener, void *data)
return;
}
- layersurface = ecalloc(1, sizeof(LayerSurface));
+ layersurface = wlr_layer_surface->data = ecalloc(1, sizeof(LayerSurface));
layersurface->type = LayerShell;
LISTEN(&wlr_layer_surface->surface->events.commit,
&layersurface->surface_commit, commitlayersurfacenotify);
LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy,
destroylayersurfacenotify);
- LISTEN(&wlr_layer_surface->events.map, &layersurface->map,
+ LISTEN(&wlr_layer_surface->surface->events.map, &layersurface->map,
maplayersurfacenotify);
- LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap,
+ LISTEN(&wlr_layer_surface->surface->events.unmap, &layersurface->unmap,
unmaplayersurfacenotify);
layersurface->layer_surface = wlr_layer_surface;
layersurface->mon = wlr_layer_surface->output->data;
- wlr_layer_surface->data = layersurface;
-
layersurface->scene_layer = wlr_scene_layer_surface_v1_create(l, wlr_layer_surface);
layersurface->scene = layersurface->scene_layer->tree;
layersurface->popups = wlr_layer_surface->surface->data = wlr_scene_tree_create(l);
@@ -915,7 +886,6 @@ createmon(struct wl_listener *listener, void *data)
m->mfact = r->mfact;
m->nmaster = r->nmaster;
wlr_output_set_scale(wlr_output, r->scale);
- wlr_xcursor_manager_load(cursor_mgr, r->scale);
m->lt[0] = m->lt[1] = r->lt;
wlr_output_set_transform(wlr_output, r->rr);
m->m.x = r->x;
@@ -933,16 +903,12 @@ createmon(struct wl_listener *listener, void *data)
/* Set up event listeners */
LISTEN(&wlr_output->events.frame, &m->frame, rendermon);
LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);
+ LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate);
wlr_output_enable(wlr_output, 1);
if (!wlr_output_commit(wlr_output))
return;
- /* Try to enable adaptive sync, note that not all monitors support it.
- * wlr_output_commit() will deactivate it in case it cannot be enabled */
- wlr_output_enable_adaptive_sync(wlr_output, 1);
- wlr_output_commit(wlr_output);
-
wl_list_insert(&mons, &m->link);
printstatus();
@@ -1006,8 +972,12 @@ createnotify(struct wl_listener *listener, void *data)
c->surface.xdg = xdg_surface;
c->bw = borderpx;
- LISTEN(&xdg_surface->events.map, &c->map, mapnotify);
- LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify);
+ wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel,
+ WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
+
+ LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify);
+ LISTEN(&xdg_surface->surface->events.map, &c->map, mapnotify);
+ LISTEN(&xdg_surface->surface->events.unmap, &c->unmap, unmapnotify);
LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify);
LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle);
LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen,
@@ -1074,8 +1044,6 @@ cursorframe(struct wl_listener *listener, void *data)
void
destroydragicon(struct wl_listener *listener, void *data)
{
- struct wlr_drag_icon *icon = data;
- wlr_scene_node_destroy(icon->data);
/* Focus enter isn't sent during drag, so refocus the focused node. */
focusclient(focustop(selmon), 1);
motionnotify(0);
@@ -1150,20 +1118,25 @@ destroylocksurface(struct wl_listener *listener, void *data)
void
destroynotify(struct wl_listener *listener, void *data)
{
- /* Called when the surface is destroyed and should never be shown again. */
+ /* Called when the xdg_toplevel is destroyed. */
Client *c = wl_container_of(listener, c, destroy);
- wl_list_remove(&c->map.link);
- wl_list_remove(&c->unmap.link);
wl_list_remove(&c->destroy.link);
wl_list_remove(&c->set_title.link);
wl_list_remove(&c->fullscreen.link);
#ifdef XWAYLAND
if (c->type != XDGShell) {
+ wl_list_remove(&c->activate.link);
+ wl_list_remove(&c->associate.link);
wl_list_remove(&c->configure.link);
+ wl_list_remove(&c->dissociate.link);
wl_list_remove(&c->set_hints.link);
- wl_list_remove(&c->activate.link);
- }
+ } else
#endif
+ {
+ wl_list_remove(&c->commit.link);
+ wl_list_remove(&c->map.link);
+ wl_list_remove(&c->unmap.link);
+ }
free(c);
}
@@ -1177,8 +1150,8 @@ destroysessionlock(struct wl_listener *listener, void *data)
void
destroysessionmgr(struct wl_listener *listener, void *data)
{
- wl_list_remove(&session_lock_create_lock.link);
- wl_list_remove(&session_lock_mgr_destroy.link);
+ wl_list_remove(&lock_listener.link);
+ wl_list_remove(&listener->link);
}
Monitor *
@@ -1427,12 +1400,11 @@ keypress(struct wl_listener *listener, void *data)
int handled = 0;
uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard);
- IDLE_NOTIFY_ACTIVITY;
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
/* On _press_ if there is no active screen locker,
* attempt to process a compositor keybinding. */
- if (!locked && !input_inhibit_mgr->active_inhibitor
- && event->state == WL_KEYBOARD_KEY_STATE_PRESSED)
+ if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED)
for (i = 0; i < nsyms; i++)
handled = keybinding(mods, syms[i]) || handled;
@@ -1509,13 +1481,12 @@ locksession(struct wl_listener *listener, void *data)
wlr_session_lock_v1_destroy(session_lock);
return;
}
- lock = ecalloc(1, sizeof(*lock));
+ lock = session_lock->data = ecalloc(1, sizeof(*lock));
focusclient(NULL, 0);
lock->scene = wlr_scene_tree_create(layers[LyrBlock]);
cur_lock = lock->lock = session_lock;
locked = 1;
- session_lock->data = lock;
LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface);
LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock);
@@ -1540,17 +1511,11 @@ mapnotify(struct wl_listener *listener, void *data)
int i;
/* Create scene tree for this client and its border */
- c->scene = wlr_scene_tree_create(layers[LyrTile]);
+ c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]);
wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell);
c->scene_surface = c->type == XDGShell
? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg)
: wlr_scene_subsurface_tree_create(c->scene, client_surface(c));
- if (client_surface(c)) {
- client_surface(c)->data = c->scene;
- /* Ideally we should do this in createnotify{,x11} but at that moment
- * wlr_xwayland_surface doesn't have wlr_surface yet. */
- LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify);
- }
c->scene->node.data = c->scene_surface->node.data = c;
/* Handle unmanaged clients first so we can return prior create borders */
@@ -1610,9 +1575,14 @@ maximizenotify(struct wl_listener *listener, void *data)
* typically because the user clicked on the maximize button on
* client-side decorations. dwl doesn't support maximization, but
* to conform to xdg-shell protocol we still must send a configure.
+ * Since xdg-shell protocol v5 we should ignore request of unsupported
+ * capabilities, just schedule a empty configure when the client uses <5
+ * protocol version
* wlr_xdg_surface_schedule_configure() is used to send an empty reply. */
Client *c = wl_container_of(listener, c, maximize);
- wlr_xdg_surface_schedule_configure(c->surface.xdg);
+ if (wl_resource_get_version(c->surface.xdg->resource)
+ < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION)
+ wlr_xdg_surface_schedule_configure(c->surface.xdg);
}
void
@@ -1658,7 +1628,7 @@ motionnotify(uint32_t time)
/* time is 0 in internal calls meant to restore pointer focus. */
if (time) {
- IDLE_NOTIFY_ACTIVITY;
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
/* Update selmon (even while dragging a window) */
if (sloppyfocus)
@@ -1696,8 +1666,8 @@ motionnotify(uint32_t time)
/* If there's no client surface under the cursor, set the cursor image to a
* default. This is what makes the cursor image appear when you move it
* off of a client or over its border. */
- if (!surface && !seat->drag && (!cursor_image || strcmp(cursor_image, "left_ptr")))
- wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor);
+ if (!surface && !seat->drag)
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
pointerfocus(c, surface, sx, sy, time);
}
@@ -1732,7 +1702,7 @@ moveresize(const Arg *arg)
case CurMove:
grabcx = cursor->x - grabc->geom.x;
grabcy = cursor->y - grabc->geom.y;
- wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "fleur"), cursor);
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
break;
case CurResize:
/* Doesn't work for X11 output - the next absolute motion event
@@ -1740,8 +1710,7 @@ moveresize(const Arg *arg)
wlr_cursor_warp_closest(cursor, NULL,
grabc->geom.x + grabc->geom.width,
grabc->geom.y + grabc->geom.height);
- wlr_xcursor_manager_set_cursor_image(cursor_mgr,
- (cursor_image = "bottom_right_corner"), cursor);
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
break;
}
}
@@ -1783,7 +1752,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)
/* Don't move monitors if position wouldn't change, this to avoid
* wlroots marking the output as manually configured */
if (m->m.x != config_head->state.x || m->m.y != config_head->state.y)
- wlr_output_layout_move(output_layout, wlr_output,
+ wlr_output_layout_add(output_layout, wlr_output,
config_head->state.x, config_head->state.y);
wlr_output_set_transform(wlr_output, config_head->state.transform);
wlr_output_set_scale(wlr_output, config_head->state.scale);
@@ -1842,6 +1811,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
* wlroots makes this a no-op if surface is already focused */
wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
wlr_seat_pointer_notify_motion(seat, time, sx, sy);
+
}
void
@@ -1898,6 +1868,8 @@ rendermon(struct wl_listener *listener, void *data)
* generally at the output's refresh rate (e.g. 60Hz). */
Monitor *m = wl_container_of(listener, m, frame);
Client *c;
+ struct wlr_output_state pending = {0};
+ struct wlr_gamma_control_v1 *gamma_control;
struct timespec now;
/* Render if no XDG clients have an outstanding resize and are visible on
@@ -1905,12 +1877,38 @@ rendermon(struct wl_listener *listener, void *data)
wl_list_for_each(c, &clients, link)
if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c))
goto skip;
- wlr_scene_output_commit(m->scene_output);
+
+ /*
+ * HACK: The "correct" way to set the gamma is to commit it together with
+ * the rest of the state in one go, but to do that we would need to rewrite
+ * wlr_scene_output_commit() in order to add the gamma to the pending
+ * state before committing, instead try to commit the gamma in one frame,
+ * and commit the rest of the state in the next one (or in the same frame if
+ * the gamma can not be committed).
+ */
+ if (m->gamma_lut_changed) {
+ gamma_control = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output);
+ m->gamma_lut_changed = 0;
+
+ if (!wlr_gamma_control_v1_apply(gamma_control, &pending))
+ goto commit;
+
+ if (!wlr_output_test_state(m->wlr_output, &pending)) {
+ wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
+ goto commit;
+ }
+ wlr_output_commit_state(m->wlr_output, &pending);
+ wlr_output_schedule_frame(m->wlr_output);
+ } else {
+commit:
+ wlr_scene_output_commit(m->scene_output, NULL);
+ }
skip:
/* Let clients know a frame has been rendered */
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_scene_output_send_frame_done(m->scene_output, &now);
+ wlr_output_state_finish(&pending);
}
void
@@ -1926,9 +1924,18 @@ requeststartdrag(struct wl_listener *listener, void *data)
}
void
+requestmonstate(struct wl_listener *listener, void *data)
+{
+ struct wlr_output_event_request_state *event = data;
+ wlr_output_commit_state(event->output, event->state);
+ updatemons(NULL, NULL);
+}
+
+void
resize(Client *c, struct wlr_box geo, int interact)
{
struct wlr_box *bbox = interact ? &sgeom : &c->mon->w;
+ struct wlr_box clip;
client_set_bounds(c, geo.width, geo.height);
c->geom = geo;
applybounds(c, bbox);
@@ -1947,6 +1954,8 @@ resize(Client *c, struct wlr_box geo, int interact)
/* this is a no-op if size hasn't changed */
c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
c->geom.height - 2 * c->bw);
+ client_get_clip(c, &clip);
+ wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
}
void
@@ -1992,7 +2001,7 @@ run(char *startup_cmd)
* initialized, as the image/coordinates are not transformed for the
* monitor when displayed here */
wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y);
- wlr_xcursor_manager_set_cursor_image(cursor_mgr, cursor_image, cursor);
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
/* Run the Wayland event loop. This does not return until you exit the
* compositor. Starting the backend rigged up all of the necessary event
@@ -2011,7 +2020,6 @@ setcursor(struct wl_listener *listener, void *data)
* event, which will result in the client requesting set the cursor surface */
if (cursor_mode != CurNormal && cursor_mode != CurPressed)
return;
- cursor_image = NULL;
/* This can be sent by any client, so we check to make sure this one is
* actually has pointer focus first. If so, we can tell the cursor to
* use the provided surface as the cursor image. It will set the
@@ -2023,6 +2031,20 @@ setcursor(struct wl_listener *listener, void *data)
}
void
+setcursorshape(struct wl_listener *listener, void *data)
+{
+ struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data;
+ if (cursor_mode != CurNormal && cursor_mode != CurPressed)
+ return;
+ /* This can be sent by any client, so we check to make sure this one is
+ * actually has pointer focus first. If so, we can tell the cursor to
+ * use the provided cursor shape. */
+ if (event->seat_client == seat->pointer_state.focused_client)
+ wlr_cursor_set_xcursor(cursor, cursor_mgr,
+ wlr_cursor_shape_v1_name(event->shape));
+}
+
+void
setfloating(Client *c, int floating)
{
c->isfloating = floating;
@@ -2058,6 +2080,15 @@ setfullscreen(Client *c, int fullscreen)
}
void
+setgamma(struct wl_listener *listener, void *data)
+{
+ struct wlr_gamma_control_manager_v1_set_gamma_event *event = data;
+ Monitor *m = event->output->data;
+ m->gamma_lut_changed = 1;
+ wlr_output_schedule_frame(m->wlr_output);
+}
+
+void
setlayout(const Arg *arg)
{
if (!selmon)
@@ -2150,12 +2181,8 @@ setup(void)
/* The backend is a wlroots feature which abstracts the underlying input and
* output hardware. The autocreate option will choose the most suitable
* backend based on the current environment, such as opening an X11 window
- * if an X11 server is running. The NULL argument here optionally allows you
- * to pass in a custom renderer if wlr_renderer doesn't meet your needs. The
- * backend uses the renderer, for example, to fall back to software cursors
- * if the backend does not support hardware cursors (some older GPUs
- * don't). */
- if (!(backend = wlr_backend_autocreate(dpy)))
+ * if an X11 server is running. */
+ if (!(backend = wlr_backend_autocreate(dpy, &session)))
die("couldn't create backend");
/* Initialize the scene graph used to lay out windows */
@@ -2165,12 +2192,30 @@ setup(void)
drag_icon = wlr_scene_tree_create(&scene->tree);
wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node);
- /* Create a renderer with the default implementation */
+ /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user
+ * can also specify a renderer using the WLR_RENDERER env var.
+ * The renderer is responsible for defining the various pixel formats it
+ * supports for shared memory, this configures that for clients. */
if (!(drw = wlr_renderer_autocreate(backend)))
die("couldn't create renderer");
- wlr_renderer_init_wl_display(drw, dpy);
- /* Create a default allocator */
+ /* Create shm, drm and linux_dmabuf interfaces by ourselves.
+ * The simplest way is call:
+ * wlr_renderer_init_wl_display(drw);
+ * but we need to create manually the linux_dmabuf interface to integrate it
+ * with wlr_scene. */
+ wlr_renderer_init_wl_shm(drw, dpy);
+
+ if (wlr_renderer_get_dmabuf_texture_formats(drw)) {
+ wlr_drm_create(dpy, drw);
+ wlr_scene_set_linux_dmabuf_v1(scene,
+ wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw));
+ }
+
+ /* Autocreates an allocator for us.
+ * The allocator is the bridge between the renderer and the backend. It
+ * handles the buffer creation, allowing wlroots to render onto the
+ * screen */
if (!(alloc = wlr_allocator_autocreate(backend, drw)))
die("couldn't create allocator");
@@ -2180,33 +2225,36 @@ setup(void)
* to dig your fingers in and play with their behavior if you want. Note that
* the clients cannot set the selection directly without compositor approval,
* see the setsel() function. */
- compositor = wlr_compositor_create(dpy, drw);
+ compositor = wlr_compositor_create(dpy, 6, drw);
+ wlr_subcompositor_create(dpy);
+ wlr_data_device_manager_create(dpy);
wlr_export_dmabuf_manager_v1_create(dpy);
wlr_screencopy_manager_v1_create(dpy);
wlr_data_control_manager_v1_create(dpy);
- wlr_data_device_manager_create(dpy);
- wlr_gamma_control_manager_v1_create(dpy);
wlr_primary_selection_v1_device_manager_create(dpy);
wlr_viewporter_create(dpy);
wlr_single_pixel_buffer_manager_v1_create(dpy);
- wlr_subcompositor_create(dpy);
+ wlr_fractional_scale_manager_v1_create(dpy, 1);
/* Initializes the interface used to implement urgency hints */
activation = wlr_xdg_activation_v1_create(dpy);
- wl_signal_add(&activation->events.request_activate, &request_activate);
+ LISTEN_STATIC(&activation->events.request_activate, urgent);
+
+ gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy);
+ LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma);
/* Creates an output layout, which a wlroots utility for working with an
* arrangement of screens in a physical layout. */
output_layout = wlr_output_layout_create();
- wl_signal_add(&output_layout->events.change, &layout_change);
+ LISTEN_STATIC(&output_layout->events.change, updatemons);
wlr_xdg_output_manager_v1_create(dpy, output_layout);
/* Configure a listener to be notified when new outputs are available on the
* backend. */
wl_list_init(&mons);
- wl_signal_add(&backend->events.new_output, &new_output);
+ LISTEN_STATIC(&backend->events.new_output, createmon);
- /* Set up our client lists and the xdg-shell. The xdg-shell is a
+ /* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a
* Wayland protocol which is used for application windows. For more
* detail on shells, refer to the article:
*
@@ -2215,22 +2263,20 @@ setup(void)
wl_list_init(&clients);
wl_list_init(&fstack);
- idle = wlr_idle_create(dpy);
- idle_notifier = wlr_idle_notifier_v1_create(dpy);
+ xdg_shell = wlr_xdg_shell_create(dpy, 6);
+ LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify);
- idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy);
- wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create);
+ layer_shell = wlr_layer_shell_v1_create(dpy, 3);
+ LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface);
- layer_shell = wlr_layer_shell_v1_create(dpy);
- wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface);
+ idle_notifier = wlr_idle_notifier_v1_create(dpy);
- xdg_shell = wlr_xdg_shell_create(dpy, 4);
- wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface);
+ idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy);
+ LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor);
- input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy);
session_lock_mgr = wlr_session_lock_manager_v1_create(dpy);
- wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock);
- wl_signal_add(&session_lock_mgr->events.destroy, &session_lock_mgr_destroy);
+ wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener);
+ LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr);
locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height,
(float [4]){0.1, 0.1, 0.1, 1.0});
wlr_scene_node_set_enabled(&locked_bg->node, 0);
@@ -2240,7 +2286,7 @@ setup(void)
wlr_server_decoration_manager_create(dpy),
WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy);
- wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration);
+ LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration);
/*
* Creates a cursor, which is a wlroots utility for tracking the cursor
@@ -2261,18 +2307,19 @@ setup(void)
* when the pointer moves. However, we can attach input devices to it, and
* it will generate aggregate events for all of them. In these events, we
* can choose how we want to process them, forwarding them to clients and
- * moving the cursor around. More detail on this process is described in my
- * input handling blog post:
- *
+ * moving the cursor around. More detail on this process is described in
* https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html
*
* And more comments are sprinkled throughout the notify functions above.
*/
- wl_signal_add(&cursor->events.motion, &cursor_motion);
- wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute);
- wl_signal_add(&cursor->events.button, &cursor_button);
- wl_signal_add(&cursor->events.axis, &cursor_axis);
- wl_signal_add(&cursor->events.frame, &cursor_frame);
+ LISTEN_STATIC(&cursor->events.motion, motionrelative);
+ LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute);
+ LISTEN_STATIC(&cursor->events.button, buttonpress);
+ LISTEN_STATIC(&cursor->events.axis, axisnotify);
+ LISTEN_STATIC(&cursor->events.frame, cursorframe);
+
+ cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
+ LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape);
/*
* Configures a seat, which is a single "seat" at which a user sits and
@@ -2281,20 +2328,19 @@ setup(void)
* let us know when new input devices are available on the backend.
*/
wl_list_init(&keyboards);
- wl_signal_add(&backend->events.new_input, &new_input);
+ LISTEN_STATIC(&backend->events.new_input, inputdevice);
virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
- wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,
- &new_virtual_keyboard);
+ LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard);
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_start_drag, &request_start_drag);
- wl_signal_add(&seat->events.start_drag, &start_drag);
+ LISTEN_STATIC(&seat->events.request_set_cursor, setcursor);
+ LISTEN_STATIC(&seat->events.request_set_selection, setsel);
+ LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel);
+ LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag);
+ LISTEN_STATIC(&seat->events.start_drag, startdrag);
output_mgr = wlr_output_manager_v1_create(dpy);
- wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
- wl_signal_add(&output_mgr->events.test, &output_mgr_test);
+ LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);
+ LISTEN_STATIC(&output_mgr->events.test, outputmgrtest);
wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend));
@@ -2305,8 +2351,8 @@ setup(void)
*/
xwayland = wlr_xwayland_create(dpy, compositor, 1);
if (xwayland) {
- wl_signal_add(&xwayland->events.ready, &xwayland_ready);
- wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface);
+ LISTEN_STATIC(&xwayland->events.ready, xwaylandready);
+ LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11);
setenv("DISPLAY", xwayland->display_name, 1);
} else {
@@ -2333,8 +2379,8 @@ startdrag(struct wl_listener *listener, void *data)
if (!drag->icon)
return;
- drag->icon->data = &wlr_scene_subsurface_tree_create(drag_icon, drag->icon->surface)->node;
- wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy);
+ drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node;
+ LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon);
}
void
@@ -2485,7 +2531,6 @@ unmapnotify(struct wl_listener *listener, void *data)
wl_list_remove(&c->flink);
}
- wl_list_remove(&c->commit.link);
wlr_scene_node_destroy(&c->scene->node);
printstatus();
motionnotify(0);
@@ -2524,7 +2569,6 @@ updatemons(struct wl_listener *listener, void *data)
if (m->wlr_output->enabled
&& !wlr_output_layout_get(output_layout, m->wlr_output))
wlr_output_layout_add_auto(output_layout, m->wlr_output);
-
/* Now that we update the output layout we can get its box */
wlr_output_layout_get_box(output_layout, NULL, &sgeom);
@@ -2538,8 +2582,8 @@ updatemons(struct wl_listener *listener, void *data)
config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
/* Get the effective monitor geometry to use for surfaces */
- wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m));
- wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->w));
+ wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m);
+ m->w = m->m;
wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);
wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y);
@@ -2556,7 +2600,11 @@ updatemons(struct wl_listener *listener, void *data)
arrangelayers(m);
/* Don't move clients to the left output when plugging monitors */
arrange(m);
+ /* make sure fullscreen clients have the right size */
+ if ((c = focustop(m)) && c->isfullscreen)
+ resize(c, m->m, 0);
+ m->gamma_lut_changed = 1;
config_head->state.enabled = 1;
config_head->state.mode = m->wlr_output->current_mode;
config_head->state.x = m->m.x;
@@ -2565,7 +2613,7 @@ updatemons(struct wl_listener *listener, void *data)
if (selmon && selmon->wlr_output->enabled) {
wl_list_for_each(c, &clients, link)
- if (!c->mon && client_is_mapped(c))
+ if (!c->mon && client_surface(c)->mapped)
setmon(c, selmon, c->tags);
focusclient(focustop(selmon), 1);
if (selmon->lock_surface) {
@@ -2575,6 +2623,13 @@ updatemons(struct wl_listener *listener, void *data)
}
}
+ /* FIXME: figure out why the cursor image is at 0,0 after turning all
+ * the monitors on.
+ * Move the cursor image where it used to be. It does not generate a
+ * wl_pointer.motion event for the clients, it's only the image what it's
+ * at the wrong position after all. */
+ wlr_cursor_move(cursor, NULL, 0, 0);
+
wlr_output_manager_v1_set_configuration(output_mgr, config);
}
@@ -2595,7 +2650,7 @@ urgent(struct wl_listener *listener, void *data)
if (!c || c == focustop(selmon))
return;
- if (client_is_mapped(c))
+ if (client_surface(c)->mapped)
client_set_border_color(c, urgentcolor);
c->isurgent = 1;
printstatus();
@@ -2643,7 +2698,7 @@ xytonode(double x, double y, struct wlr_surface **psurface,
continue;
if (node->type == WLR_SCENE_NODE_BUFFER)
- surface = wlr_scene_surface_from_buffer(
+ surface = wlr_scene_surface_try_from_buffer(
wlr_scene_buffer_from_node(node))->surface;
/* Walk the tree to find a node that knows the client */
for (pnode = node; pnode && !c; pnode = &pnode->parent->node)
@@ -2703,6 +2758,15 @@ activatex11(struct wl_listener *listener, void *data)
}
void
+associatex11(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, associate);
+
+ LISTEN(&client_surface(c)->events.map, &c->map, mapnotify);
+ LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify);
+}
+
+void
configurex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, configure);
@@ -2729,8 +2793,8 @@ createnotifyx11(struct wl_listener *listener, void *data)
c->bw = borderpx;
/* Listen to the various events it can emit */
- LISTEN(&xsurface->events.map, &c->map, mapnotify);
- LISTEN(&xsurface->events.unmap, &c->unmap, unmapnotify);
+ LISTEN(&xsurface->events.associate, &c->associate, associatex11);
+ LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11);
LISTEN(&xsurface->events.request_activate, &c->activate, activatex11);
LISTEN(&xsurface->events.request_configure, &c->configure, configurex11);
LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints);
@@ -2739,6 +2803,14 @@ createnotifyx11(struct wl_listener *listener, void *data)
LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify);
}
+void
+dissociatex11(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, dissociate);
+ wl_list_remove(&c->map.link);
+ wl_list_remove(&c->unmap.link);
+}
+
xcb_atom_t
getatom(xcb_connection_t *xc, const char *name)
{
@@ -2756,12 +2828,13 @@ void
sethints(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, set_hints);
+ struct wlr_surface *surface = client_surface(c);
if (c == focustop(selmon))
return;
c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
- if (c->isurgent && client_is_mapped(c))
+ if (c->isurgent && surface && surface->mapped)
client_set_border_color(c, urgentcolor);
printstatus();
@@ -2789,7 +2862,7 @@ xwaylandready(struct wl_listener *listener, void *data)
wlr_xwayland_set_seat(xwayland, seat);
/* Set the default XWayland cursor to match the rest of dwl. */
- if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "left_ptr", 1)))
+ if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1)))
wlr_xwayland_set_cursor(xwayland,
xcursor->images[0]->buffer, xcursor->images[0]->width * 4,
xcursor->images[0]->width, xcursor->images[0]->height,