20 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
3 changed files with 238 additions and 46 deletions
+30 -1
View File
@@ -141,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;
}
@@ -255,6 +255,32 @@ client_is_rendered_on_mon(Client *c, Monitor *m)
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)
{
@@ -319,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);
}
+1 -1
View File
@@ -1,4 +1,4 @@
_VERSION = 0.4-rc2
_VERSION = 0.4-rc3
VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)`
PKG_CONFIG = pkg-config
+207 -44
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 */
@@ -201,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);
@@ -218,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);
@@ -228,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);
@@ -241,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);
@@ -261,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);
@@ -280,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);
@@ -296,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;
@@ -307,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;
@@ -320,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;
@@ -345,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};
@@ -354,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);
@@ -450,6 +478,7 @@ arrange(Monitor *m)
if (m && m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m);
motionnotify(0);
checkidleinhibitor(NULL);
}
void
@@ -503,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;
@@ -543,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)))
@@ -557,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
@@ -597,8 +629,8 @@ checkidleinhibitor(struct wlr_surface *exclude)
wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) {
struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface);
struct wlr_scene_tree *tree = surface->data;
if (bypass_surface_visibility || (exclude != surface
&& tree->node.enabled)) {
if (exclude != surface && (bypass_surface_visibility || (!tree
|| tree->node.enabled))) {
inhibited = 1;
break;
}
@@ -729,12 +761,24 @@ commitnotify(struct wl_listener *listener, void *data)
struct wlr_box box = {0};
client_get_geometry(c, &box);
if (c->mon && !wlr_box_empty(&box) && (box.width != c->geom.width - 2 * c->bw
|| box.height != c->geom.height - 2 * c->bw))
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))
if (c->resize && (c->resize <= c->surface.xdg->current.configure_serial
|| (c->surface.xdg->current.geometry.width == c->surface.xdg->pending.geometry.width
&& c->surface.xdg->current.geometry.height == c->surface.xdg->pending.geometry.height)))
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)
{
@@ -822,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)
{
@@ -910,11 +973,11 @@ createnotify(struct wl_listener *listener, void *data)
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
struct wlr_box box;
int type = toplevel_from_wlr_surface(xdg_surface->surface, &c, &l);
if (!xdg_surface->popup->parent)
if (!xdg_surface->popup->parent || type < 0)
return;
xdg_surface->surface->data = wlr_scene_xdg_surface_create(
xdg_surface->popup->parent->data, xdg_surface);
if ((!l || !l->mon) || (!c || !c->mon))
if ((l && !l->mon) || (c && !c->mon))
return;
box = type == LayerShell ? l->mon->m : c->mon->w;
box.x -= (type == LayerShell ? l->geom.x : c->geom.x);
@@ -1000,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);
}
@@ -1026,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)
{
@@ -1046,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)
{
@@ -1068,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);
@@ -1112,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 */
@@ -1147,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) {
@@ -1270,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;
@@ -1304,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)
{
@@ -1327,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));
@@ -1386,7 +1533,7 @@ mapnotify(struct wl_listener *listener, void *data)
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);
}
@@ -1662,6 +1809,7 @@ printstatus(void)
sel, urg);
printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol);
}
fflush(stdout);
}
void
@@ -1688,7 +1836,7 @@ rendermon(struct wl_listener *listener, void *data)
/* Render if no XDG clients have an outstanding resize and are visible on
* this monitor. */
wl_list_for_each(c, &clients, link)
if (client_is_rendered_on_mon(c, m) && (!c->isfloating && c->resize))
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;
@@ -1788,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)
{
@@ -1929,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();
@@ -1966,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)))
@@ -2030,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
@@ -2136,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);
@@ -2148,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);
}
@@ -2189,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);
@@ -2198,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);
}
@@ -2207,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);
@@ -2232,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)
{
@@ -2246,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);
}
@@ -2264,7 +2415,7 @@ unmapnotify(struct wl_listener *listener, void *data)
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);
@@ -2312,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;
@@ -2329,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);
}
@@ -2357,7 +2520,7 @@ urgent(struct wl_listener *listener, void *data)
struct wlr_xdg_activation_v1_request_activate_event *event = data;
Client *c = NULL;
int type = toplevel_from_wlr_surface(event->surface, &c, NULL);
if (type >= 0 && type != LayerShell && c != selclient()) {
if (type >= 0 && type != LayerShell && c != focustop(selmon)) {
c->isurgent = 1;
printstatus();
}
@@ -2399,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))) {
@@ -2427,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;
@@ -2521,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();
}