33 Commits

Author SHA1 Message Date
Leonardo Hernández Hernández 05f4e23c43 bump version to 0.4-rc3 2022-12-24 17:54:19 -06:00
Leonardo Hernández Hernández be854cab35 do not try to resize if size wouldn't change 2022-12-24 16:44:09 -06:00
Leonardo Hernández Hernández 6ca011430a do not skip frames if a client is stopped and have a pending resize 2022-12-24 16:44:09 -06:00
Leonardo Hernández Hernández 7eaa01ac1f Revert "Revert "fix flickering when resizing/spawning windows""
This reverts commit 4a32293548.
2022-12-24 16:44:09 -06:00
Leonardo Hernández Hernández 92e7752203 disable client's scene node after create it (only XDGShell)
will be enabled when setting up its monitor and arrange it

Bug: https://github.com/djpohly/dwl/issues/306
2022-12-24 16:44:09 -06:00
Leonardo Hernández Hernández 6682878009 call arrange() or resize() depending on c->isfloating in commitnotify 2022-12-24 16:43:31 -06:00
Leonardo Hernández Hernández afacc9b0b5 force SSD when creating an xdg_toplevel_decoration object
Closes: https://github.com/djpohly/dwl/issues/366
Not sure why GLFW apps do not get mapped when we do not tell them the
decoration method
2022-12-20 21:53:45 -06:00
Leonardo Hernández Hernández dd9d8d543c remove selclient()
selclient() does not work well when dealing newly mapped
clients (specifically those mapped on invisible tags).

This fixes various bugs related to things not working because selclient() would
return NULL.

References: 94c8bd6048
2022-12-20 21:27:14 -06:00
Leonardo Hernández Hernández 686958a4cc fix unset fullscreen for all visible clients when mapping a new one
this also changes our policy about when we unset fullscreen:

dwl will unset fullscreen for clients who share tags (and monitor) with a newly
mapped client, it does not matter if the clients are visible or not
2022-12-20 21:21:40 -06:00
Leonardo Hernández Hernández 1a3d89e5b2 call checkidleinhibitor() in arrange() and not in focusclient() 2022-12-16 18:54:33 -06:00
Leonardo Hernández Hernández 7b1fe7e5f2 fix checking idle inhibit state
checking `bypass_surface_visibility` first, could cause that even if the idle
inhibitor is being destroyed it will disable idle tracking

and if we couldn't get its scene tree, then assume that the surface is visible
2022-12-16 17:37:18 -06:00
Leonardo Hernández Hernández 803a9ba98d Revert "Revert "Check that inhibitor scene tree is not null""
This reverts commit 035bb99d67.

Not checking `tree != NULL` result in a segfault if the surface doesn't have a
role (for example because it is a newly created surface)

Closes: https://github.com/djpohly/dwl/issues/359
2022-12-16 17:20:59 -06:00
Ben Jargowsky a39a46c908 Check width and height are not negative in client_set_bounds() 2022-12-15 23:42:53 -06:00
Leonardo Hernández Hernández 94c8bd6048 get sel from focustop() in focusstack()
Fixes: https://github.com/djpohly/dwl/issues/354
2022-12-09 20:55:58 -06:00
Leonardo Hernández Hernández c60f651951 Revert "force line-buffered stdout if stdout is not a tty"
This reverts commit deb48ff48b.

Fixes: https://github.com/djpohly/dwl/issues/253
2022-12-09 08:46:22 -06:00
Leonardo Hernández Hernández 79b051f242 implement ext-session-lock-v1 2022-12-06 14:11:41 -06:00
Leonardo Hernández Hernández d42a977b5b Revert "remove unneeded changes in commitnotify()"
This reverts commit 30c24a53ad.

Bug: https://github.com/djpohly/dwl/issues/349
2022-12-06 13:59:14 -06:00
Leonardo Hernández Hernández 4a32293548 Revert "fix flickering when resizing/spawning windows"
This reverts commit 017bb7d752.

Bug: https://github.com/djpohly/dwl/issues/349
2022-12-06 13:58:56 -06:00
Leonardo Hernández Hernández 9136b6247d return early if couldn't find the popup's parent 2022-12-06 13:34:35 -06:00
Leonardo Hernández Hernández 19b5d47a9e fix popups appearing outside the monitor
and a potentially crash
2022-12-06 13:31:48 -06:00
Leonardo Hernández Hernández c9a0a8bf6d bump version to 0.4-rc2 2022-12-05 23:21:21 -06:00
Leonardo Hernández Hernández 22336612ae improve type safety of toplevel_from_wlr_surface() 2022-12-05 23:18:02 -06:00
Leonardo Hernández Hernández 38bd00351a merge toplevel_from_{wlr_layer_surface,popup} into client_from_wlr_surface
now it is a big function called toplevel_from_wlr_surface
2022-12-05 23:18:01 -06:00
Leonardo Hernández Hernández c56bc42eb5 sort client_get_parent() 2022-12-05 23:18:01 -06:00
Leonardo Hernández Hernández 13b929d7d7 remove unneeded call to wlr_scene_rect_set_color()
wlr_scene_rect_create() requires a color as parameter
2022-12-05 23:06:53 -06:00
Leonardo Hernández Hernández b6d6127733 add option for set button map 2022-12-05 22:22:49 -06:00
Dima Krasner 16a49e9955 fix null deref in sigchld() if Xwayland is disabled 2022-12-03 13:30:30 -06:00
Palanix 30c24a53ad remove unneeded changes in commitnotify() 2022-12-03 13:14:10 -06:00
Palanix 017bb7d752 fix flickering when resizing/spawning windows
Fixes: https://github.com/djpohly/dwl/issues/306
2022-12-03 13:14:10 -06:00
Leonardo Hernández Hernández fac3b6f2cf use root surfaces to check idle inhibitors
References: https://github.com/djpohly/dwl/pull/343
2022-12-02 23:25:46 -06:00
Leonardo Hernández Hernández 035bb99d67 Revert "Check that inhibitor scene tree is not null"
This reverts commit 9c155eefdc.

This commit was applied just a workaround, the proper fix is the next commit
2022-12-02 23:25:04 -06:00
Ben Jargowsky 9c155eefdc Check that inhibitor scene tree is not null 2022-12-02 15:10:25 -06:00
Jan Beich df34fdd483 chase default terminal in manpage after 7710cf050d 2022-12-02 10:52:34 -06:00
5 changed files with 364 additions and 171 deletions
+122 -75
View File
@@ -16,40 +16,6 @@ client_is_x11(Client *c)
#endif
}
static inline Client *
client_from_wlr_surface(struct wlr_surface *s)
{
struct wlr_xdg_surface *surface;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xsurface;
if (s && wlr_surface_is_xwayland_surface(s)
&& (xsurface = wlr_xwayland_surface_from_wlr_surface(s)))
return xsurface->data;
#endif
if (s && wlr_surface_is_xdg_surface(s)
&& (surface = wlr_xdg_surface_from_wlr_surface(s))
&& surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL)
return surface->data;
if (s && wlr_surface_is_subsurface(s))
return client_from_wlr_surface(wlr_surface_get_root_surface(s));
return NULL;
}
static inline Client *
client_get_parent(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c) && c->surface.xwayland->parent)
return client_from_wlr_surface(c->surface.xwayland->parent->surface);
#endif
if (c->surface.xdg->toplevel->parent)
return client_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface);
return NULL;
}
static inline void
client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min)
{
@@ -85,6 +51,69 @@ client_surface(Client *c)
return c->surface.xdg->surface;
}
static inline int
toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
{
struct wlr_xdg_surface *xdg_surface;
struct wlr_surface *root_surface;
struct wlr_layer_surface_v1 *layer_surface;
Client *c = NULL;
LayerSurface *l = NULL;
int type = -1;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xsurface;
#endif
if (!s)
return type;
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))) {
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))) {
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:
return -1;
}
}
}
end:
if (pl)
*pl = l;
if (pc)
*pc = c;
return type;
}
/* The others */
static inline void
client_activate_surface(struct wlr_surface *s, int activated)
@@ -112,7 +141,7 @@ client_set_bounds(Client *c, int32_t width, int32_t height)
return 0;
#endif
if (c->surface.xdg->client->shell->version >=
XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION)
XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0)
return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height);
return 0;
}
@@ -153,6 +182,20 @@ client_get_geometry(Client *c, struct wlr_box *geom)
wlr_xdg_surface_get_geometry(c->surface.xdg, geom);
}
static inline Client *
client_get_parent(Client *c)
{
Client *p = NULL;
#ifdef XWAYLAND
if (client_is_x11(c) && c->surface.xwayland->parent)
toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
#endif
if (c->surface.xdg->toplevel->parent)
toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
return p;
}
static inline const char *
client_get_title(Client *c)
{
@@ -197,6 +240,47 @@ client_is_mapped(Client *c)
return c->surface.xdg->mapped;
}
static inline int
client_is_rendered_on_mon(Client *c, Monitor *m)
{
/* This is needed for when you don't want to check formal assignment,
* but rather actual displaying of the pixels.
* Usually VISIBLEON suffices and is also faster. */
struct wlr_surface_output *s;
if (!c->scene->node.enabled)
return 0;
wl_list_for_each(s, &client_surface(c)->current_outputs, link)
if (s->output == m->wlr_output)
return 1;
return 0;
}
static inline int
client_is_stopped(Client *c)
{
int pid;
siginfo_t in = {0};
#ifdef XWAYLAND
if (client_is_x11(c))
return 0;
#endif
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
/* This process is not our child process, while is very unluckely that
* it is stopped, in order to do not skip frames assume that it is. */
if (errno == ECHILD)
return 1;
} else if (in.si_pid) {
if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
return 1;
if (in.si_code == CLD_CONTINUED)
return 0;
}
return 0;
}
static inline int
client_is_unmanaged(Client *c)
{
@@ -261,6 +345,9 @@ client_set_size(Client *c, uint32_t width, uint32_t height)
return 0;
}
#endif
if (width == c->surface.xdg->toplevel->current.width
&& height ==c->surface.xdg->toplevel->current.height)
return 0;
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, width, height);
}
@@ -305,43 +392,3 @@ client_wants_fullscreen(Client *c)
#endif
return c->surface.xdg->toplevel->requested.fullscreen;
}
static inline void *
toplevel_from_popup(struct wlr_xdg_popup *popup)
{
struct wlr_xdg_surface *surface = popup->base;
while (1) {
switch (surface->role) {
case WLR_XDG_SURFACE_ROLE_POPUP:
if (!surface->popup->parent)
return NULL;
else if (wlr_surface_is_layer_surface(surface->popup->parent))
return wlr_layer_surface_v1_from_wlr_surface(surface->popup->parent)->data;
else if (!wlr_surface_is_xdg_surface(surface->popup->parent))
return NULL;
surface = wlr_xdg_surface_from_wlr_surface(surface->popup->parent);
break;
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
return surface->data;
case WLR_XDG_SURFACE_ROLE_NONE:
return NULL;
}
}
}
static inline void *
toplevel_from_wlr_layer_surface(struct wlr_surface *s)
{
Client *c;
struct wlr_layer_surface_v1 *wlr_layer_surface;
if ((c = client_from_wlr_surface(s)))
return c;
else if (s && wlr_surface_is_layer_surface(s)
&& (wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(s)))
return wlr_layer_surface->data;
return NULL;
}
+5
View File
@@ -85,6 +85,11 @@ LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
*/
static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
static const double accel_speed = 0.0;
/* You can choose between:
LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle
LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
*/
static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
#define MODKEY WLR_MODIFIER_ALT
+1 -1
View File
@@ -1,4 +1,4 @@
_VERSION = 0.4-rc1
_VERSION = 0.4-rc3
VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)`
PKG_CONFIG = pkg-config
+2 -2
View File
@@ -51,7 +51,7 @@ Spawn
.Nm bemenu-run .
.It Mod-Shift-Return
Spawn
.Nm alacritty .
.Nm foot .
.It Mod-[jk]
Move focus down/up the stack.
.It Mod-[id]
@@ -135,7 +135,7 @@ Start
with s6 in the background:
.Dl dwl -s 's6-svscan <&-'
.Sh SEE ALSO
.Xr alacritty 1 ,
.Xr foot 1 ,
.Xr bemenu 1 ,
.Xr dwm 1 ,
.Xr xkeyboard-config 7
+234 -93
View File
@@ -40,6 +40,7 @@
#include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_session_lock_v1.h>
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_viewporter.h>
@@ -73,7 +74,7 @@
/* enums */
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */
enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, NUM_LAYERS }; /* scene layers */
enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, LyrBlock, NUM_LAYERS }; /* scene layers */
#ifdef XWAYLAND
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
@@ -173,6 +174,8 @@ struct Monitor {
struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
struct wl_listener frame;
struct wl_listener destroy;
struct wl_listener destroy_lock_surface;
struct wlr_session_lock_surface_v1 *lock_surface;
struct wlr_box m; /* monitor area, layout-relative */
struct wlr_box w; /* window area, layout-relative */
struct wl_list layers[4]; /* LayerSurface::link */
@@ -182,7 +185,6 @@ struct Monitor {
unsigned int tagset[2];
double mfact;
int nmaster;
int un_map; /* If a map/unmap happened on this monitor, then this should be true */
};
typedef struct {
@@ -202,6 +204,15 @@ typedef struct {
int monitor;
} Rule;
typedef struct {
struct wlr_scene_tree *scene;
struct wlr_session_lock_v1 *lock;
struct wl_listener new_surface;
struct wl_listener unlock;
struct wl_listener destroy;
} SessionLock;
/* function declarations */
static void applybounds(Client *c, struct wlr_box *bbox);
static void applyrules(Client *c);
@@ -219,9 +230,11 @@ static void cleanupmon(struct wl_listener *listener, void *data);
static void closemon(Monitor *m);
static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
static void commitnotify(struct wl_listener *listener, void *data);
static void createdecoration(struct wl_listener *listener, void *data);
static void createidleinhibitor(struct wl_listener *listener, void *data);
static void createkeyboard(struct wlr_keyboard *keyboard);
static void createlayersurface(struct wl_listener *listener, void *data);
static void createlocksurface(struct wl_listener *listener, void *data);
static void createmon(struct wl_listener *listener, void *data);
static void createnotify(struct wl_listener *listener, void *data);
static void createpointer(struct wlr_pointer *pointer);
@@ -229,7 +242,11 @@ static void cursorframe(struct wl_listener *listener, void *data);
static void destroydragicon(struct wl_listener *listener, void *data);
static void destroyidleinhibitor(struct wl_listener *listener, void *data);
static void destroylayersurfacenotify(struct wl_listener *listener, void *data);
static void destroylock(SessionLock *lock, int unlocked);
static void destroylocksurface(struct wl_listener *listener, void *data);
static void destroynotify(struct wl_listener *listener, void *data);
static void destroysessionlock(struct wl_listener *listener, void *data);
static void destroysessionmgr(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
@@ -242,6 +259,7 @@ static int keybinding(uint32_t mods, xkb_keysym_t sym);
static void keypress(struct wl_listener *listener, void *data);
static void keypressmod(struct wl_listener *listener, void *data);
static void killclient(const Arg *arg);
static void locksession(struct wl_listener *listener, void *data);
static void maplayersurfacenotify(struct wl_listener *listener, void *data);
static void mapnotify(struct wl_listener *listener, void *data);
static void maximizenotify(struct wl_listener *listener, void *data);
@@ -262,7 +280,6 @@ static void rendermon(struct wl_listener *listener, void *data);
static void requeststartdrag(struct wl_listener *listener, void *data);
static void resize(Client *c, struct wlr_box geo, int interact);
static void run(char *startup_cmd);
static Client *selclient(void);
static void setcursor(struct wl_listener *listener, void *data);
static void setfloating(Client *c, int floating);
static void setfullscreen(Client *c, int fullscreen);
@@ -281,6 +298,7 @@ static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unlocksession(struct wl_listener *listener, void *data);
static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
static void unmapnotify(struct wl_listener *listener, void *data);
static void updatemons(struct wl_listener *listener, void *data);
@@ -297,6 +315,7 @@ static void zoom(const Arg *arg);
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;
static struct wl_display *dpy;
static struct wlr_backend *backend;
@@ -308,6 +327,7 @@ static struct wlr_compositor *compositor;
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;
@@ -321,6 +341,10 @@ static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
static struct wlr_cursor *cursor;
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 wlr_seat *seat;
static struct wl_list keyboards;
static unsigned int cursor_mode;
@@ -346,6 +370,7 @@ 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};
@@ -355,6 +380,8 @@ 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);
@@ -451,6 +478,7 @@ arrange(Monitor *m)
if (m && m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m);
motionnotify(0);
checkidleinhibitor(NULL);
}
void
@@ -504,8 +532,8 @@ arrangelayers(Monitor *m)
for (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->mapped) {
if (!locked && layersurface->layer_surface->current.keyboard_interactive
&& layersurface->mapped) {
/* Deactivate the focused client. */
focusclient(NULL, 0);
exclusive_focus = layersurface;
@@ -544,6 +572,10 @@ buttonpress(struct wl_listener *listener, void *data)
switch (event->state) {
case WLR_BUTTON_PRESSED:
cursor_mode = CurPressed;
if (locked)
break;
/* Change focus if the button was _pressed_ over a client */
xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
if (c && (!client_is_unmanaged(c) || client_wants_focus(c)))
@@ -558,11 +590,10 @@ buttonpress(struct wl_listener *listener, void *data)
return;
}
}
cursor_mode = CurPressed;
break;
case WLR_BUTTON_RELEASED:
/* If you released any buttons, we exit interactive move/resize mode. */
if (cursor_mode != CurNormal && cursor_mode != CurPressed) {
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
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
@@ -596,9 +627,10 @@ checkidleinhibitor(struct wlr_surface *exclude)
int inhibited = 0;
struct wlr_idle_inhibitor_v1 *inhibitor;
wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) {
struct wlr_scene_tree *tree = inhibitor->surface->data;
if (bypass_surface_visibility || (exclude != inhibitor->surface
&& tree->node.enabled)) {
struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface);
struct wlr_scene_tree *tree = surface->data;
if (exclude != surface && (bypass_surface_visibility || (!tree
|| tree->node.enabled))) {
inhibited = 1;
break;
}
@@ -731,7 +763,7 @@ commitnotify(struct wl_listener *listener, void *data)
if (c->mon && !wlr_box_empty(&box) && (box.width != c->geom.width - 2 * c->bw
|| box.height != c->geom.height - 2 * c->bw))
arrange(c->mon);
c->isfloating ? resize(c, c->geom, 1) : arrange(c->mon);
/* mark a pending resize as completed */
if (c->resize && (c->resize <= c->surface.xdg->current.configure_serial
@@ -740,6 +772,13 @@ commitnotify(struct wl_listener *listener, void *data)
c->resize = 0;
}
void
createdecoration(struct wl_listener *listener, void *data)
{
struct wlr_xdg_toplevel_decoration_v1 *dec = data;
wlr_xdg_toplevel_decoration_v1_set_mode(dec, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
void
createidleinhibitor(struct wl_listener *listener, void *data)
{
@@ -827,6 +866,25 @@ createlayersurface(struct wl_listener *listener, void *data)
wlr_layer_surface->current = old_state;
}
void
createlocksurface(struct wl_listener *listener, void *data)
{
SessionLock *lock = wl_container_of(listener, lock, new_surface);
struct wlr_session_lock_surface_v1 *lock_surface = data;
Monitor *m = lock_surface->output->data;
struct wlr_scene_tree *scene_tree = lock_surface->surface->data =
wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface);
m->lock_surface = lock_surface;
wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height);
LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, destroylocksurface);
if (m == selmon)
client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat));
}
void
createmon(struct wl_listener *listener, void *data)
{
@@ -909,22 +967,21 @@ createnotify(struct wl_listener *listener, void *data)
* If you want to do something tricky with popups you should check if
* its parent is wlr_xdg_shell or wlr_layer_shell */
struct wlr_xdg_surface *xdg_surface = data;
Client *c;
Client *c = NULL;
LayerSurface *l = NULL;
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
struct wlr_box box;
LayerSurface *l = toplevel_from_popup(xdg_surface->popup);
if (!xdg_surface->popup->parent)
int type = toplevel_from_wlr_surface(xdg_surface->surface, &c, &l);
if (!xdg_surface->popup->parent || type < 0)
return;
xdg_surface->surface->data = wlr_scene_xdg_surface_create(
xdg_surface->popup->parent->data, xdg_surface);
/* Probably the check of `l` is useless, the only thing that can be NULL
* is its monitor */
if (!l || !l->mon)
if ((l && !l->mon) || (c && !c->mon))
return;
box = l->type == LayerShell ? l->mon->m : l->mon->w;
box.x -= l->geom.x;
box.y -= l->geom.y;
box = type == LayerShell ? l->mon->m : c->mon->w;
box.x -= (type == LayerShell ? l->geom.x : c->geom.x);
box.y -= (type == LayerShell ? l->geom.y : c->geom.y);
wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box);
return;
} else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE)
@@ -956,6 +1013,7 @@ createpointer(struct wlr_pointer *pointer)
libinput_device_config_tap_set_enabled(libinput_device, tap_to_click);
libinput_device_config_tap_set_drag_enabled(libinput_device, tap_and_drag);
libinput_device_config_tap_set_drag_lock_enabled(libinput_device, drag_lock);
libinput_device_config_tap_set_button_map(libinput_device, button_map);
}
if (libinput_device_config_scroll_has_natural_scroll(libinput_device))
@@ -1005,7 +1063,7 @@ 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(selclient(), 1);
focusclient(focustop(selmon), 1);
motionnotify(0);
}
@@ -1014,7 +1072,7 @@ destroyidleinhibitor(struct wl_listener *listener, void *data)
{
/* `data` is the wlr_surface of the idle inhibitor being destroyed,
* at this point the idle inhibitor is still in the list of the manager */
checkidleinhibitor(data);
checkidleinhibitor(wlr_surface_get_root_surface(data));
}
void
@@ -1031,6 +1089,49 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data)
free(layersurface);
}
void
destroylock(SessionLock *lock, int unlock)
{
wlr_seat_keyboard_notify_clear_focus(seat);
if ((locked = !unlock))
goto destroy;
wlr_scene_node_set_enabled(&locked_bg->node, 0);
focusclient(focustop(selmon), 0);
motionnotify(0);
destroy:
wl_list_remove(&lock->new_surface.link);
wl_list_remove(&lock->unlock.link);
wl_list_remove(&lock->destroy.link);
wlr_scene_node_destroy(&lock->scene->node);
cur_lock = NULL;
free(lock);
}
void
destroylocksurface(struct wl_listener *listener, void *data)
{
Monitor *m = wl_container_of(listener, m, destroy_lock_surface);
struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface;
m->lock_surface = NULL;
wl_list_remove(&m->destroy_lock_surface.link);
if (lock_surface->surface == seat->keyboard_state.focused_surface) {
if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) {
surface = wl_container_of(cur_lock->surfaces.next, surface, link);
client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat));
} else if (!locked) {
focusclient(focustop(selmon), 1);
} else {
wlr_seat_keyboard_clear_focus(seat);
}
}
}
void
destroynotify(struct wl_listener *listener, void *data)
{
@@ -1051,6 +1152,20 @@ destroynotify(struct wl_listener *listener, void *data)
free(c);
}
void
destroysessionlock(struct wl_listener *listener, void *data)
{
SessionLock *lock = wl_container_of(listener, lock, destroy);
destroylock(lock, 0);
}
void
destroysessionmgr(struct wl_listener *listener, void *data)
{
wl_list_remove(&session_lock_create_lock.link);
wl_list_remove(&session_lock_mgr_destroy.link);
}
Monitor *
dirtomon(enum wlr_direction dir)
{
@@ -1073,6 +1188,9 @@ focusclient(Client *c, int lift)
struct wlr_surface *old = seat->keyboard_state.focused_surface;
int i;
if (locked)
return;
/* Raise client in stacking order if requested */
if (c && lift)
wlr_scene_node_raise_to_top(&c->scene->node);
@@ -1100,15 +1218,12 @@ focusclient(Client *c, int lift)
/* If an overlay is focused, don't focus or activate the client,
* but only update its position in fstack to render its border with focuscolor
* and focus it after the overlay is closed. */
Client *w = client_from_wlr_surface(old);
if (wlr_surface_is_layer_surface(old)) {
struct wlr_layer_surface_v1 *wlr_layer_surface =
wlr_layer_surface_v1_from_wlr_surface(old);
if (wlr_layer_surface && ((LayerSurface *)wlr_layer_surface->data)->mapped
&& (wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP
|| wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY))
return;
Client *w = NULL;
LayerSurface *l = NULL;
int type = toplevel_from_wlr_surface(old, &w, &l);
if (type == LayerShell && l->scene->node.enabled
&& l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
return;
} else if (w && w == exclusive_focus && client_wants_focus(w)) {
return;
/* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg
@@ -1120,9 +1235,7 @@ focusclient(Client *c, int lift)
client_activate_surface(old, 0);
}
}
printstatus();
checkidleinhibitor(NULL);
if (!c) {
/* With no client, all we have left is to clear focus */
@@ -1155,7 +1268,7 @@ void
focusstack(const Arg *arg)
{
/* Focus the next or previous client (in tiling order) on selmon */
Client *c, *sel = selclient();
Client *c, *sel = focustop(selmon);
if (!sel || sel->isfullscreen)
return;
if (arg->i > 0) {
@@ -1278,7 +1391,7 @@ keypress(struct wl_listener *listener, void *data)
/* On _press_ if there is no active screen locker,
* attempt to process a compositor keybinding. */
if (!input_inhibit_mgr->active_inhibitor
if (!locked && !input_inhibit_mgr->active_inhibitor
&& event->state == WL_KEYBOARD_KEY_STATE_PRESSED)
for (i = 0; i < nsyms; i++)
handled = keybinding(mods, syms[i]) || handled;
@@ -1312,11 +1425,36 @@ keypressmod(struct wl_listener *listener, void *data)
void
killclient(const Arg *arg)
{
Client *sel = selclient();
Client *sel = focustop(selmon);
if (sel)
client_send_close(sel);
}
void
locksession(struct wl_listener *listener, void *data)
{
struct wlr_session_lock_v1 *session_lock = data;
SessionLock *lock;
wlr_scene_node_set_enabled(&locked_bg->node, 1);
if (cur_lock) {
wlr_session_lock_v1_destroy(session_lock);
return;
}
lock = 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);
LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession);
wlr_session_lock_v1_send_locked(session_lock);
}
void
maplayersurfacenotify(struct wl_listener *listener, void *data)
{
@@ -1335,6 +1473,7 @@ mapnotify(struct wl_listener *listener, void *data)
/* Create scene tree for this client and its border */
c->scene = 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));
@@ -1365,7 +1504,6 @@ mapnotify(struct wl_listener *listener, void *data)
for (i = 0; i < 4; i++) {
c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor);
c->border[i]->node.data = c;
wlr_scene_rect_set_color(c->border[i], bordercolor);
}
/* Initialize client geometry with room for border */
@@ -1392,12 +1530,10 @@ mapnotify(struct wl_listener *listener, void *data)
}
printstatus();
c->mon->un_map = 1;
unset_fullscreen:
m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y);
wl_list_for_each(w, &clients, link)
if (w != c && w->isfullscreen && VISIBLEON(w, m))
if (w != c && w->isfullscreen && m == w->mon && (w->tags & c->tags))
setfullscreen(w, 0);
}
@@ -1445,8 +1581,9 @@ void
motionnotify(uint32_t time)
{
double sx = 0, sy = 0;
Client *c = NULL;
LayerSurface *l;
Client *c = NULL, *w = NULL;
LayerSurface *l = NULL;
int type;
struct wlr_surface *surface = NULL;
struct wlr_drag_icon *icon;
@@ -1479,11 +1616,12 @@ motionnotify(uint32_t time)
xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy);
if (cursor_mode == CurPressed && !seat->drag) {
if ((l = toplevel_from_wlr_layer_surface(
seat->pointer_state.focused_surface))) {
if ((type = toplevel_from_wlr_surface(
seat->pointer_state.focused_surface, &w, &l)) >= 0) {
c = w;
surface = seat->pointer_state.focused_surface;
sx = cursor->x - l->geom.x;
sy = cursor->y - l->geom.y;
sx = cursor->x - (type == LayerShell ? l->geom.x : w->geom.x);
sy = cursor->y - (type == LayerShell ? l->geom.y : w->geom.y);
}
}
@@ -1671,6 +1809,7 @@ printstatus(void)
sel, urg);
printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol);
}
fflush(stdout);
}
void
@@ -1692,30 +1831,19 @@ 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;
int skip = 0;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
/* Render if no XDG clients have an outstanding resize and are visible on
* this monitor. */
/* Checking m->un_map for every client is not optimal but works */
wl_list_for_each(c, &clients, link) {
if ((c->resize && m->un_map) || (c->type == XDGShell
&& (c->surface.xdg->pending.geometry.width !=
c->surface.xdg->current.geometry.width
|| c->surface.xdg->pending.geometry.height !=
c->surface.xdg->current.geometry.height))) {
/* Lie */
wlr_surface_send_frame_done(client_surface(c), &now);
skip = 1;
}
}
if (!skip && !wlr_scene_output_commit(m->scene_output))
wl_list_for_each(c, &clients, link)
if (client_is_rendered_on_mon(c, m) && (!c->isfloating && c->resize) && !client_is_stopped(c))
goto skip;
if (!wlr_scene_output_commit(m->scene_output))
return;
skip:
/* Let clients know a frame has been rendered */
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_scene_output_send_frame_done(m->scene_output, &now);
m->un_map = 0;
}
void
@@ -1808,15 +1936,6 @@ run(char *startup_cmd)
wl_display_run(dpy);
}
Client *
selclient(void)
{
Client *c = wl_container_of(fstack.next, c, flink);
if (wl_list_empty(&fstack) || !VISIBLEON(c, selmon))
return NULL;
return c;
}
void
setcursor(struct wl_listener *listener, void *data)
{
@@ -1949,9 +2068,6 @@ setsel(struct wl_listener *listener, void *data)
void
setup(void)
{
/* Force line-buffered stdout */
setvbuf(stdout, NULL, _IOLBF, 0);
/* The Wayland display is managed by libwayland. It handles accepting
* clients from the Unix socket, manging Wayland globals, and so on. */
dpy = wl_display_create();
@@ -1986,6 +2102,7 @@ setup(void)
layers[LyrTop] = wlr_scene_tree_create(&scene->tree);
layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree);
layers[LyrDragIcon] = wlr_scene_tree_create(&scene->tree);
layers[LyrBlock] = wlr_scene_tree_create(&scene->tree);
/* Create a renderer with the default implementation */
if (!(drw = wlr_renderer_autocreate(backend)))
@@ -2050,12 +2167,19 @@ setup(void)
wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface);
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);
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);
/* Use decoration protocols to negotiate server-side decorations */
wlr_server_decoration_manager_set_default_mode(
wlr_server_decoration_manager_create(dpy),
WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
wlr_xdg_decoration_manager_v1_create(dpy);
xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy);
wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration);
/*
* Creates a cursor, which is a wlroots utility for tracking the cursor
@@ -2156,7 +2280,7 @@ startdrag(struct wl_listener *listener, void *data)
void
tag(const Arg *arg)
{
Client *sel = selclient();
Client *sel = focustop(selmon);
if (sel && arg->ui & TAGMASK) {
sel->tags = arg->ui & TAGMASK;
focusclient(focustop(selmon), 1);
@@ -2168,7 +2292,7 @@ tag(const Arg *arg)
void
tagmon(const Arg *arg)
{
Client *sel = selclient();
Client *sel = focustop(selmon);
if (sel)
setmon(sel, dirtomon(arg->i), 0);
}
@@ -2209,7 +2333,7 @@ tile(Monitor *m)
void
togglefloating(const Arg *arg)
{
Client *sel = selclient();
Client *sel = focustop(selmon);
/* return if fullscreen */
if (sel && !sel->isfullscreen)
setfloating(sel, !sel->isfloating);
@@ -2218,7 +2342,7 @@ togglefloating(const Arg *arg)
void
togglefullscreen(const Arg *arg)
{
Client *sel = selclient();
Client *sel = focustop(selmon);
if (sel)
setfullscreen(sel, !sel->isfullscreen);
}
@@ -2227,7 +2351,7 @@ void
toggletag(const Arg *arg)
{
unsigned int newtags;
Client *sel = selclient();
Client *sel = focustop(selmon);
if (!sel)
return;
newtags = sel->tags ^ (arg->ui & TAGMASK);
@@ -2252,6 +2376,13 @@ toggleview(const Arg *arg)
printstatus();
}
void
unlocksession(struct wl_listener *listener, void *data)
{
SessionLock *lock = wl_container_of(listener, lock, unlock);
destroylock(lock, 1);
}
void
unmaplayersurfacenotify(struct wl_listener *listener, void *data)
{
@@ -2266,7 +2397,7 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data)
arrangelayers(layersurface->mon);
if (layersurface->layer_surface->surface ==
seat->keyboard_state.focused_surface)
focusclient(selclient(), 1);
focusclient(focustop(selmon), 1);
motionnotify(0);
}
@@ -2280,14 +2411,11 @@ unmapnotify(struct wl_listener *listener, void *data)
grabc = NULL;
}
if (c->mon)
c->mon->un_map = 1;
if (client_is_unmanaged(c)) {
if (c == exclusive_focus)
exclusive_focus = NULL;
if (client_surface(c) == seat->keyboard_state.focused_surface)
focusclient(selclient(), 1);
focusclient(focustop(selmon), 1);
} else {
wl_list_remove(&c->link);
setmon(c, NULL, 0);
@@ -2335,6 +2463,7 @@ updatemons(struct wl_listener *listener, void *data)
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);
wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height);
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled)
continue;
@@ -2352,16 +2481,27 @@ updatemons(struct wl_listener *listener, void *data)
wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y);
wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height);
if (m->lock_surface) {
struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data;
wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width,
m->m.height);
}
config_head->state.enabled = 1;
config_head->state.mode = m->wlr_output->current_mode;
config_head->state.x = m->m.x;
config_head->state.y = m->m.y;
}
if (selmon && selmon->wlr_output->enabled)
if (selmon && selmon->wlr_output->enabled) {
wl_list_for_each(c, &clients, link)
if (!c->mon && client_is_mapped(c))
setmon(c, selmon, c->tags);
if (selmon->lock_surface)
client_notify_enter(selmon->lock_surface->surface,
wlr_seat_get_keyboard(seat));
}
wlr_output_manager_v1_set_configuration(output_mgr, config);
}
@@ -2378,8 +2518,9 @@ void
urgent(struct wl_listener *listener, void *data)
{
struct wlr_xdg_activation_v1_request_activate_event *event = data;
Client *c = client_from_wlr_surface(event->surface);
if (c && c != selclient()) {
Client *c = NULL;
int type = toplevel_from_wlr_surface(event->surface, &c, NULL);
if (type >= 0 && type != LayerShell && c != focustop(selmon)) {
c->isurgent = 1;
printstatus();
}
@@ -2421,7 +2562,7 @@ xytonode(double x, double y, struct wlr_surface **psurface,
Client *c = NULL;
LayerSurface *l = NULL;
const int *layer;
int focus_order[] = { LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg };
int focus_order[] = { LyrBlock, LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg };
for (layer = focus_order; layer < END(focus_order); layer++) {
if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) {
@@ -2449,7 +2590,7 @@ xytonode(double x, double y, struct wlr_surface **psurface,
void
zoom(const Arg *arg)
{
Client *c, *sel = selclient();
Client *c, *sel = focustop(selmon);
if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating)
return;
@@ -2543,7 +2684,7 @@ void
sethints(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, set_hints);
if (c != selclient()) {
if (c != focustop(selmon)) {
c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
printstatus();
}
@@ -2564,7 +2705,7 @@ sigchld(int unused)
* XWayland process
*/
while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid
&& in.si_pid != xwayland->server->pid)
&& (!xwayland || in.si_pid != xwayland->server->pid))
waitpid(in.si_pid, NULL, 0);
}