3 Commits

Author SHA1 Message Date
3e0d6772d6 added ipc protocol 2025-04-06 01:09:07 +02:00
408517fb7a added patch file to ipc branch 2025-04-06 00:10:22 +02:00
95d88401d9 cleaned branch 2025-03-31 00:58:25 +02:00
5 changed files with 1045 additions and 420 deletions

View File

@@ -17,12 +17,14 @@ DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEV
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
all: dwl
dwl: dwl.o util.o
$(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
dwl: dwl.o util.o dwl-ipc-unstable-v2-protocol.o
$(CC) dwl.o util.o dwl-ipc-unstable-v2-protocol.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \
dwl-ipc-unstable-v2-protocol.h
util.o: util.c util.h
dwl-ipc-unstable-v2-protocol.o: dwl-ipc-unstable-v2-protocol.c dwl-ipc-unstable-v2-protocol.h
# wayland-scanner is a tool which generates C headers and rigging for Wayland
# protocols, which are specified in XML. wlroots requires you to rig these up
@@ -45,6 +47,12 @@ wlr-output-power-management-unstable-v1-protocol.h:
xdg-shell-protocol.h:
$(WAYLAND_SCANNER) server-header \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
dwl-ipc-unstable-v2-protocol.h:
$(WAYLAND_SCANNER) server-header \
protocols/dwl-ipc-unstable-v2.xml $@
dwl-ipc-unstable-v2-protocol.c:
$(WAYLAND_SCANNER) private-code \
protocols/dwl-ipc-unstable-v2.xml $@
config.h:
cp config.def.h $@

342
dwl.c
View File

@@ -68,6 +68,7 @@
#include <xcb/xcb_icccm.h>
#endif
#include "dwl-ipc-unstable-v2-protocol.h"
#include "util.h"
/* macros */
@@ -141,6 +142,12 @@ typedef struct {
uint32_t resize; /* configure serial of a pending resize */
} Client;
typedef struct {
struct wl_list link;
struct wl_resource *resource;
Monitor *mon;
} DwlIpcOutput;
typedef struct {
uint32_t mod;
xkb_keysym_t keysym;
@@ -185,6 +192,7 @@ typedef struct {
struct Monitor {
struct wl_list link;
struct wl_list dwl_ipc_outputs;
struct wlr_output *wlr_output;
struct wlr_scene_output *scene_output;
struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
@@ -282,14 +290,24 @@ static void destroypointerconstraint(struct wl_listener *listener, void *data);
static void destroysessionlock(struct wl_listener *listener, void *data);
static void destroykeyboardgroup(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir);
static void dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id);
static void dwl_ipc_manager_destroy(struct wl_resource *resource);
static void dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output);
static void dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource);
static void dwl_ipc_output_destroy(struct wl_resource *resource);
static void dwl_ipc_output_printstatus(Monitor *monitor);
static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output);
static void dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags);
static void dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index);
static void dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset);
static void dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
static Client *focustop(Monitor *m, int onlytiled);
static Client *focustop(Monitor *m);
static void fullscreennotify(struct wl_listener *listener, void *data);
static void gpureset(struct wl_listener *listener, void *data);
static void handlesig(int signo);
static void hidebehindmonocle(Monitor *m);
static void incnmaster(const Arg *arg);
static void inputdevice(struct wl_listener *listener, void *data);
static int keybinding(uint32_t mods, xkb_keysym_t sym);
@@ -335,6 +353,7 @@ static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *m);
static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
@@ -437,6 +456,9 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag};
static struct wl_listener start_drag = {.notify = startdrag};
static struct wl_listener new_session_lock = {.notify = locksession};
static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = {.release = dwl_ipc_manager_release, .get_output = dwl_ipc_manager_get_output};
static struct zdwl_ipc_output_v2_interface dwl_output_implementation = {.release = dwl_ipc_output_release, .set_tags = dwl_ipc_output_set_tags, .set_layout = dwl_ipc_output_set_layout, .set_client_tags = dwl_ipc_output_set_client_tags};
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
@@ -519,7 +541,7 @@ arrange(Monitor *m)
}
wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
(c = focustop(m, 0)) && c->isfullscreen);
(c = focustop(m)) && c->isfullscreen);
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
@@ -730,6 +752,10 @@ cleanupmon(struct wl_listener *listener, void *data)
LayerSurface *l, *tmp;
size_t i;
DwlIpcOutput *ipc_output, *ipc_output_tmp;
wl_list_for_each_safe(ipc_output, ipc_output_tmp, &m->dwl_ipc_outputs, link)
wl_resource_destroy(ipc_output->resource);
/* m->layers[i] are intentionally not unlinked */
for (i = 0; i < LENGTH(m->layers); i++) {
wl_list_for_each_safe(l, tmp, &m->layers[i], link)
@@ -811,7 +837,7 @@ closemon(Monitor *m)
if (c->mon == m)
setmon(c, selmon, c->tags);
}
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
printstatus();
}
@@ -1050,6 +1076,8 @@ createmon(struct wl_listener *listener, void *data)
m = wlr_output->data = ecalloc(1, sizeof(*m));
m->wlr_output = wlr_output;
wl_list_init(&m->dwl_ipc_outputs);
for (i = 0; i < LENGTH(m->layers); i++)
wl_list_init(&m->layers[i]);
@@ -1248,7 +1276,7 @@ void
destroydragicon(struct wl_listener *listener, void *data)
{
/* Focus enter isn't sent during drag, so refocus the focused node. */
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
motionnotify(0, NULL, 0, 0, 0, 0);
wl_list_remove(&listener->link);
free(listener);
@@ -1287,7 +1315,7 @@ destroylock(SessionLock *lock, int unlock)
wlr_scene_node_set_enabled(&locked_bg->node, 0);
focusclient(focustop(selmon, 0), 0);
focusclient(focustop(selmon), 0);
motionnotify(0, NULL, 0, 0, 0, 0);
destroy:
@@ -1316,7 +1344,7 @@ destroylocksurface(struct wl_listener *listener, void *data)
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, 0), 1);
focusclient(focustop(selmon), 1);
} else {
wlr_seat_keyboard_clear_focus(seat);
}
@@ -1397,6 +1425,192 @@ dirtomon(enum wlr_direction dir)
return selmon;
}
void
dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
struct wl_resource *manager_resource = wl_resource_create(client, &zdwl_ipc_manager_v2_interface, version, id);
if (!manager_resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(manager_resource, &dwl_manager_implementation, NULL, dwl_ipc_manager_destroy);
zdwl_ipc_manager_v2_send_tags(manager_resource, TAGCOUNT);
for (unsigned int i = 0; i < LENGTH(layouts); i++)
zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol);
}
void
dwl_ipc_manager_destroy(struct wl_resource *resource)
{
/* No state to destroy */
}
void
dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output)
{
DwlIpcOutput *ipc_output;
Monitor *monitor = wlr_output_from_resource(output)->data;
struct wl_resource *output_resource = wl_resource_create(client, &zdwl_ipc_output_v2_interface, wl_resource_get_version(resource), id);
if (!output_resource)
return;
ipc_output = ecalloc(1, sizeof(*ipc_output));
ipc_output->resource = output_resource;
ipc_output->mon = monitor;
wl_resource_set_implementation(output_resource, &dwl_output_implementation, ipc_output, dwl_ipc_output_destroy);
wl_list_insert(&monitor->dwl_ipc_outputs, &ipc_output->link);
dwl_ipc_output_printstatus_to(ipc_output);
}
void
dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
dwl_ipc_output_destroy(struct wl_resource *resource)
{
DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource);
wl_list_remove(&ipc_output->link);
free(ipc_output);
}
void
dwl_ipc_output_printstatus(Monitor *monitor)
{
DwlIpcOutput *ipc_output;
wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link)
dwl_ipc_output_printstatus_to(ipc_output);
}
void
dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output)
{
Monitor *monitor = ipc_output->mon;
Client *c, *focused;
int tagmask, state, numclients, focused_client, tag;
const char *title, *appid;
focused = focustop(monitor);
zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon);
for (tag = 0 ; tag < TAGCOUNT; tag++) {
numclients = state = focused_client = 0;
tagmask = 1 << tag;
if ((tagmask & monitor->tagset[monitor->seltags]) != 0)
state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE;
wl_list_for_each(c, &clients, link) {
if (c->mon != monitor)
continue;
if (!(c->tags & tagmask))
continue;
if (c == focused)
focused_client = 1;
if (c->isurgent)
state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT;
numclients++;
}
zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, numclients, focused_client);
}
title = focused ? client_get_title(focused) : "";
appid = focused ? client_get_appid(focused) : "";
zdwl_ipc_output_v2_send_layout(ipc_output->resource, monitor->lt[monitor->sellt] - layouts);
zdwl_ipc_output_v2_send_title(ipc_output->resource, title);
zdwl_ipc_output_v2_send_appid(ipc_output->resource, appid);
zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, monitor->ltsymbol);
if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) {
zdwl_ipc_output_v2_send_fullscreen(ipc_output->resource, focused ? focused->isfullscreen : 0);
}
if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) {
zdwl_ipc_output_v2_send_floating(ipc_output->resource, focused ? focused->isfloating : 0);
}
zdwl_ipc_output_v2_send_frame(ipc_output->resource);
}
void
dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags)
{
DwlIpcOutput *ipc_output;
Monitor *monitor;
Client *selected_client;
unsigned int newtags = 0;
ipc_output = wl_resource_get_user_data(resource);
if (!ipc_output)
return;
monitor = ipc_output->mon;
selected_client = focustop(monitor);
if (!selected_client)
return;
newtags = (selected_client->tags & and_tags) ^ xor_tags;
if (!newtags)
return;
selected_client->tags = newtags;
if (selmon == monitor)
focusclient(focustop(monitor), 1);
arrange(selmon);
printstatus();
}
void
dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index)
{
DwlIpcOutput *ipc_output;
Monitor *monitor;
ipc_output = wl_resource_get_user_data(resource);
if (!ipc_output)
return;
monitor = ipc_output->mon;
if (index >= LENGTH(layouts))
return;
if (index != monitor->lt[monitor->sellt] - layouts)
monitor->sellt ^= 1;
monitor->lt[monitor->sellt] = &layouts[index];
arrange(monitor);
printstatus();
}
void
dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset)
{
DwlIpcOutput *ipc_output;
Monitor *monitor;
unsigned int newtags = tagmask & TAGMASK;
ipc_output = wl_resource_get_user_data(resource);
if (!ipc_output)
return;
monitor = ipc_output->mon;
if (!newtags || newtags == monitor->tagset[monitor->seltags])
return;
if (toggle_tagset)
monitor->seltags ^= 1;
monitor->tagset[monitor->seltags] = newtags;
if (selmon == monitor)
focusclient(focustop(monitor), 1);
arrange(monitor);
printstatus();
}
void
dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
void
focusclient(Client *c, int lift)
{
@@ -1427,7 +1641,6 @@ focusclient(Client *c, int lift)
wl_list_insert(&fstack, &c->flink);
selmon = c->mon;
c->isurgent = 0;
hidebehindmonocle(c->mon);
/* Don't change border color if there is an exclusive focus or we are
* handling a drag operation */
@@ -1481,14 +1694,14 @@ focusmon(const Arg *arg)
selmon = dirtomon(arg->i);
while (!selmon->wlr_output->enabled && i++ < nmons);
}
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
}
void
focusstack(const Arg *arg)
{
/* Focus the next or previous client (in tiling order) on selmon */
Client *c, *sel = focustop(selmon, 0);
Client *c, *sel = focustop(selmon);
if (!sel || (sel->isfullscreen && !client_has_children(sel)))
return;
if (arg->i > 0) {
@@ -1514,16 +1727,13 @@ focusstack(const Arg *arg)
* will focus the topmost client of this mon, when actually will
* only return that client */
Client *
focustop(Monitor *m, int onlytiled)
focustop(Monitor *m)
{
Client *c;
wl_list_for_each(c, &fstack, flink) {
if (VISIBLEON(c, m)) {
if (onlytiled && c->isfloating)
continue;
if (VISIBLEON(c, m))
return c;
}
}
return NULL;
}
@@ -1568,25 +1778,6 @@ handlesig(int signo)
quit(NULL);
}
void
hidebehindmonocle(Monitor *m)
{
Client *c;
if (m && m->lt[m->sellt]->arrange == monocle) {
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m) && c->isfloating);
}
c = NULL;
/* Enable top tiled client, fullscreen is considered tiled */
if ((c = focustop(m, 1)))
wlr_scene_node_set_enabled(&c->scene->node, 1);
}
}
void
incnmaster(const Arg *arg)
{
@@ -1725,7 +1916,7 @@ keyrepeat(void *data)
void
killclient(const Arg *arg)
{
Client *sel = focustop(selmon, 0);
Client *sel = focustop(selmon);
if (sel)
client_send_close(sel);
}
@@ -1854,7 +2045,8 @@ monocle(Monitor *m)
}
if (n)
snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n);
hidebehindmonocle(m);
if ((c = focustop(m)))
wlr_scene_node_raise_to_top(&c->scene->node);
}
void
@@ -2109,38 +2301,9 @@ void
printstatus(void)
{
Monitor *m = NULL;
Client *c;
uint32_t occ, urg, sel;
wl_list_for_each(m, &mons, link) {
occ = urg = 0;
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
occ |= c->tags;
if (c->isurgent)
urg |= c->tags;
}
if ((c = focustop(m, 0))) {
printf("%s title %s\n", m->wlr_output->name, client_get_title(c));
printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c));
printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen);
printf("%s floating %d\n", m->wlr_output->name, c->isfloating);
sel = c->tags;
} else {
printf("%s title \n", m->wlr_output->name);
printf("%s appid \n", m->wlr_output->name);
printf("%s fullscreen \n", m->wlr_output->name);
printf("%s floating \n", m->wlr_output->name);
sel = 0;
}
printf("%s selmon %u\n", m->wlr_output->name, m == selmon);
printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n",
m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg);
printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol);
}
fflush(stdout);
wl_list_for_each(m, &mons, link)
dwl_ipc_output_printstatus(m);
}
void
@@ -2435,7 +2598,7 @@ setmon(Client *c, Monitor *m, uint32_t newtags)
setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
setfloating(c, c->isfloating);
}
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
}
void
@@ -2664,6 +2827,8 @@ setup(void)
wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
wl_signal_add(&output_mgr->events.test, &output_mgr_test);
wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind);
/* Make sure XWayland clients don't connect to the parent X server,
* e.g when running in the x11 backend or the wayland backend and the
* compositor has Xwayland support */
@@ -2709,12 +2874,12 @@ startdrag(struct wl_listener *listener, void *data)
void
tag(const Arg *arg)
{
Client *sel = focustop(selmon, 0);
Client *sel = focustop(selmon);
if (!sel || (arg->ui & TAGMASK) == 0)
return;
sel->tags = arg->ui & TAGMASK;
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
arrange(selmon);
printstatus();
}
@@ -2722,7 +2887,7 @@ tag(const Arg *arg)
void
tagmon(const Arg *arg)
{
Client *sel = focustop(selmon, 0);
Client *sel = focustop(selmon);
if (sel)
setmon(sel, dirtomon(arg->i), 0);
}
@@ -2761,10 +2926,17 @@ tile(Monitor *m)
}
}
void
togglebar(const Arg *arg) {
DwlIpcOutput *ipc_output;
wl_list_for_each(ipc_output, &selmon->dwl_ipc_outputs, link)
zdwl_ipc_output_v2_send_toggle_visibility(ipc_output->resource);
}
void
togglefloating(const Arg *arg)
{
Client *sel = focustop(selmon, 0);
Client *sel = focustop(selmon);
/* return if fullscreen */
if (sel && !sel->isfullscreen)
setfloating(sel, !sel->isfloating);
@@ -2773,7 +2945,7 @@ togglefloating(const Arg *arg)
void
togglefullscreen(const Arg *arg)
{
Client *sel = focustop(selmon, 0);
Client *sel = focustop(selmon);
if (sel)
setfullscreen(sel, !sel->isfullscreen);
}
@@ -2782,12 +2954,12 @@ void
toggletag(const Arg *arg)
{
uint32_t newtags;
Client *sel = focustop(selmon, 0);
Client *sel = focustop(selmon);
if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK)))
return;
sel->tags = newtags;
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
arrange(selmon);
printstatus();
}
@@ -2800,7 +2972,7 @@ toggleview(const Arg *arg)
return;
selmon->tagset[selmon->seltags] = newtagset;
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
arrange(selmon);
printstatus();
}
@@ -2824,7 +2996,7 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data)
if (l->layer_surface->output && (l->mon = l->layer_surface->output->data))
arrangelayers(l->mon);
if (l->layer_surface->surface == seat->keyboard_state.focused_surface)
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
motionnotify(0, NULL, 0, 0, 0, 0);
}
@@ -2841,7 +3013,7 @@ unmapnotify(struct wl_listener *listener, void *data)
if (client_is_unmanaged(c)) {
if (c == exclusive_focus) {
exclusive_focus = NULL;
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
}
} else {
wl_list_remove(&c->link);
@@ -2922,7 +3094,7 @@ updatemons(struct wl_listener *listener, void *data)
/* 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, 0)) && c->isfullscreen)
if ((c = focustop(m)) && c->isfullscreen)
resize(c, m->m, 0);
/* Try to re-set the gamma LUT when updating monitors,
@@ -2942,7 +3114,7 @@ updatemons(struct wl_listener *listener, void *data)
if (!c->mon && client_surface(c)->mapped)
setmon(c, selmon, c->tags);
}
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
if (selmon->lock_surface) {
client_notify_enter(selmon->lock_surface->surface,
wlr_seat_get_keyboard(seat));
@@ -2964,7 +3136,7 @@ void
updatetitle(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, set_title);
if (c == focustop(c->mon, 0))
if (c == focustop(c->mon))
printstatus();
}
@@ -2974,7 +3146,7 @@ urgent(struct wl_listener *listener, void *data)
struct wlr_xdg_activation_v1_request_activate_event *event = data;
Client *c = NULL;
toplevel_from_wlr_surface(event->surface, &c, NULL);
if (!c || c == focustop(selmon, 0))
if (!c || c == focustop(selmon))
return;
c->isurgent = 1;
@@ -2992,7 +3164,7 @@ view(const Arg *arg)
selmon->seltags ^= 1; /* toggle sel tagset */
if (arg->ui & TAGMASK)
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
focusclient(focustop(selmon, 0), 1);
focusclient(focustop(selmon), 1);
arrange(selmon);
printstatus();
}
@@ -3063,7 +3235,7 @@ xytonode(double x, double y, struct wlr_surface **psurface,
void
zoom(const Arg *arg)
{
Client *c, *sel = focustop(selmon, 0);
Client *c, *sel = focustop(selmon);
if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating)
return;
@@ -3174,7 +3346,7 @@ 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, 0) || !c->surface.xwayland->hints)
if (c == focustop(selmon) || !c->surface.xwayland->hints)
return;
c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);

View File

@@ -1,332 +0,0 @@
From 8022376ee59d616831271dbc9f289a8bfd4fedda Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?=
<leohdz172@proton.me>
Date: Sat, 8 Jul 2023 17:25:16 -0600
Subject: [PATCH] hide behind monocle
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Leonardo Hernández Hernández <leohdz172@proton.me>
---
dwl.c | 87 +++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 55 insertions(+), 32 deletions(-)
diff --git a/dwl.c b/dwl.c
index ad21e1ba..cad3b0b2 100644
--- a/dwl.c
+++ b/dwl.c
@@ -285,10 +285,11 @@ static Monitor *dirtomon(enum wlr_direction dir);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
-static Client *focustop(Monitor *m);
+static Client *focustop(Monitor *m, int onlytiled);
static void fullscreennotify(struct wl_listener *listener, void *data);
static void gpureset(struct wl_listener *listener, void *data);
static void handlesig(int signo);
+static void hidebehindmonocle(Monitor *m);
static void incnmaster(const Arg *arg);
static void inputdevice(struct wl_listener *listener, void *data);
static int keybinding(uint32_t mods, xkb_keysym_t sym);
@@ -518,7 +519,7 @@ arrange(Monitor *m)
}
wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
- (c = focustop(m)) && c->isfullscreen);
+ (c = focustop(m, 0)) && c->isfullscreen);
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
@@ -807,7 +808,7 @@ closemon(Monitor *m)
if (c->mon == m)
setmon(c, selmon, c->tags);
}
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
printstatus();
}
@@ -1243,7 +1244,7 @@ void
destroydragicon(struct wl_listener *listener, void *data)
{
/* Focus enter isn't sent during drag, so refocus the focused node. */
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
motionnotify(0, NULL, 0, 0, 0, 0);
wl_list_remove(&listener->link);
}
@@ -1280,7 +1281,7 @@ destroylock(SessionLock *lock, int unlock)
wlr_scene_node_set_enabled(&locked_bg->node, 0);
- focusclient(focustop(selmon), 0);
+ focusclient(focustop(selmon, 0), 0);
motionnotify(0, NULL, 0, 0, 0, 0);
destroy:
@@ -1309,7 +1310,7 @@ destroylocksurface(struct wl_listener *listener, void *data)
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);
+ focusclient(focustop(selmon, 0), 1);
} else {
wlr_seat_keyboard_clear_focus(seat);
}
@@ -1420,6 +1421,7 @@ focusclient(Client *c, int lift)
wl_list_insert(&fstack, &c->flink);
selmon = c->mon;
c->isurgent = 0;
+ hidebehindmonocle(c->mon);
/* Don't change border color if there is an exclusive focus or we are
* handling a drag operation */
@@ -1473,14 +1475,14 @@ focusmon(const Arg *arg)
selmon = dirtomon(arg->i);
while (!selmon->wlr_output->enabled && i++ < nmons);
}
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
}
void
focusstack(const Arg *arg)
{
/* Focus the next or previous client (in tiling order) on selmon */
- Client *c, *sel = focustop(selmon);
+ Client *c, *sel = focustop(selmon, 0);
if (!sel || (sel->isfullscreen && !client_has_children(sel)))
return;
if (arg->i > 0) {
@@ -1506,12 +1508,15 @@ focusstack(const Arg *arg)
* will focus the topmost client of this mon, when actually will
* only return that client */
Client *
-focustop(Monitor *m)
+focustop(Monitor *m, int onlytiled)
{
Client *c;
wl_list_for_each(c, &fstack, flink) {
- if (VISIBLEON(c, m))
+ if (VISIBLEON(c, m)) {
+ if (onlytiled && c->isfloating)
+ continue;
return c;
+ }
}
return NULL;
}
@@ -1557,6 +1562,25 @@ handlesig(int signo)
quit(NULL);
}
+void
+hidebehindmonocle(Monitor *m)
+{
+ Client *c;
+ if (m && m->lt[m->sellt]->arrange == monocle) {
+ wl_list_for_each(c, &clients, link) {
+ if (c->mon != m)
+ continue;
+ wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m) && c->isfloating);
+ }
+
+ c = NULL;
+
+ /* Enable top tiled client, fullscreen is considered tiled */
+ if ((c = focustop(m, 1)))
+ wlr_scene_node_set_enabled(&c->scene->node, 1);
+ }
+}
+
void
incnmaster(const Arg *arg)
{
@@ -1695,7 +1719,7 @@ keyrepeat(void *data)
void
killclient(const Arg *arg)
{
- Client *sel = focustop(selmon);
+ Client *sel = focustop(selmon, 0);
if (sel)
client_send_close(sel);
}
@@ -1824,8 +1848,7 @@ monocle(Monitor *m)
}
if (n)
snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n);
- if ((c = focustop(m)))
- wlr_scene_node_raise_to_top(&c->scene->node);
+ hidebehindmonocle(m);
}
void
@@ -2092,7 +2115,7 @@ printstatus(void)
if (c->isurgent)
urg |= c->tags;
}
- if ((c = focustop(m))) {
+ if ((c = focustop(m, 0))) {
printf("%s title %s\n", m->wlr_output->name, client_get_title(c));
printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c));
printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen);
@@ -2406,7 +2429,7 @@ setmon(Client *c, Monitor *m, uint32_t newtags)
setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
setfloating(c, c->isfloating);
}
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
}
void
@@ -2680,12 +2703,12 @@ startdrag(struct wl_listener *listener, void *data)
void
tag(const Arg *arg)
{
- Client *sel = focustop(selmon);
+ Client *sel = focustop(selmon, 0);
if (!sel || (arg->ui & TAGMASK) == 0)
return;
sel->tags = arg->ui & TAGMASK;
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
arrange(selmon);
printstatus();
}
@@ -2693,7 +2716,7 @@ tag(const Arg *arg)
void
tagmon(const Arg *arg)
{
- Client *sel = focustop(selmon);
+ Client *sel = focustop(selmon, 0);
if (sel)
setmon(sel, dirtomon(arg->i), 0);
}
@@ -2735,7 +2758,7 @@ tile(Monitor *m)
void
togglefloating(const Arg *arg)
{
- Client *sel = focustop(selmon);
+ Client *sel = focustop(selmon, 0);
/* return if fullscreen */
if (sel && !sel->isfullscreen)
setfloating(sel, !sel->isfloating);
@@ -2744,7 +2767,7 @@ togglefloating(const Arg *arg)
void
togglefullscreen(const Arg *arg)
{
- Client *sel = focustop(selmon);
+ Client *sel = focustop(selmon, 0);
if (sel)
setfullscreen(sel, !sel->isfullscreen);
}
@@ -2753,12 +2776,12 @@ void
toggletag(const Arg *arg)
{
uint32_t newtags;
- Client *sel = focustop(selmon);
+ Client *sel = focustop(selmon, 0);
if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK)))
return;
sel->tags = newtags;
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
arrange(selmon);
printstatus();
}
@@ -2771,7 +2794,7 @@ toggleview(const Arg *arg)
return;
selmon->tagset[selmon->seltags] = newtagset;
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
arrange(selmon);
printstatus();
}
@@ -2795,7 +2818,7 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data)
if (l->layer_surface->output && (l->mon = l->layer_surface->output->data))
arrangelayers(l->mon);
if (l->layer_surface->surface == seat->keyboard_state.focused_surface)
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
motionnotify(0, NULL, 0, 0, 0, 0);
}
@@ -2812,7 +2835,7 @@ unmapnotify(struct wl_listener *listener, void *data)
if (client_is_unmanaged(c)) {
if (c == exclusive_focus) {
exclusive_focus = NULL;
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
}
} else {
wl_list_remove(&c->link);
@@ -2893,7 +2916,7 @@ updatemons(struct wl_listener *listener, void *data)
/* 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)
+ if ((c = focustop(m, 0)) && c->isfullscreen)
resize(c, m->m, 0);
/* Try to re-set the gamma LUT when updating monitors,
@@ -2913,7 +2936,7 @@ updatemons(struct wl_listener *listener, void *data)
if (!c->mon && client_surface(c)->mapped)
setmon(c, selmon, c->tags);
}
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
if (selmon->lock_surface) {
client_notify_enter(selmon->lock_surface->surface,
wlr_seat_get_keyboard(seat));
@@ -2935,7 +2958,7 @@ void
updatetitle(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, set_title);
- if (c == focustop(c->mon))
+ if (c == focustop(c->mon, 0))
printstatus();
}
@@ -2945,7 +2968,7 @@ urgent(struct wl_listener *listener, void *data)
struct wlr_xdg_activation_v1_request_activate_event *event = data;
Client *c = NULL;
toplevel_from_wlr_surface(event->surface, &c, NULL);
- if (!c || c == focustop(selmon))
+ if (!c || c == focustop(selmon, 0))
return;
c->isurgent = 1;
@@ -2963,7 +2986,7 @@ view(const Arg *arg)
selmon->seltags ^= 1; /* toggle sel tagset */
if (arg->ui & TAGMASK)
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
- focusclient(focustop(selmon), 1);
+ focusclient(focustop(selmon, 0), 1);
arrange(selmon);
printstatus();
}
@@ -3034,7 +3057,7 @@ xytonode(double x, double y, struct wlr_surface **psurface,
void
zoom(const Arg *arg)
{
- Client *c, *sel = focustop(selmon);
+ Client *c, *sel = focustop(selmon, 0);
if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating)
return;
@@ -3145,7 +3168,7 @@ 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))
+ if (c == focustop(selmon, 0))
return;
c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
--
2.48.0

596
ipc.patch Normal file
View File

@@ -0,0 +1,596 @@
From 6c6d655b68770ce82a24fde9b58c4d97b672553a Mon Sep 17 00:00:00 2001
From: choc <notchoc@proton.me>
Date: Mon, 23 Oct 2023 10:35:17 +0800
Subject: [PATCH] implement dwl-ipc-unstable-v2
https://codeberg.org/dwl/dwl-patches/wiki/ipc
---
Makefile | 14 +-
config.def.h | 1 +
dwl.c | 257 ++++++++++++++++++++++++++----
protocols/dwl-ipc-unstable-v2.xml | 181 +++++++++++++++++++++
4 files changed, 419 insertions(+), 34 deletions(-)
create mode 100644 protocols/dwl-ipc-unstable-v2.xml
diff --git a/Makefile b/Makefile
index 8db7409..a79a080 100644
--- a/Makefile
+++ b/Makefile
@@ -17,12 +17,14 @@ DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEV
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
all: dwl
-dwl: dwl.o util.o
- $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
+dwl: dwl.o util.o dwl-ipc-unstable-v2-protocol.o
+ $(CC) dwl.o util.o dwl-ipc-unstable-v2-protocol.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
- wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
+ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \
+ dwl-ipc-unstable-v2-protocol.h
util.o: util.c util.h
+dwl-ipc-unstable-v2-protocol.o: dwl-ipc-unstable-v2-protocol.c dwl-ipc-unstable-v2-protocol.h
# wayland-scanner is a tool which generates C headers and rigging for Wayland
# protocols, which are specified in XML. wlroots requires you to rig these up
@@ -45,6 +47,12 @@ wlr-output-power-management-unstable-v1-protocol.h:
xdg-shell-protocol.h:
$(WAYLAND_SCANNER) server-header \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
+dwl-ipc-unstable-v2-protocol.h:
+ $(WAYLAND_SCANNER) server-header \
+ protocols/dwl-ipc-unstable-v2.xml $@
+dwl-ipc-unstable-v2-protocol.c:
+ $(WAYLAND_SCANNER) private-code \
+ protocols/dwl-ipc-unstable-v2.xml $@
config.h:
cp config.def.h $@
diff --git a/config.def.h b/config.def.h
index 22d2171..1593033 100644
--- a/config.def.h
+++ b/config.def.h
@@ -127,6 +127,7 @@ static const Key keys[] = {
/* modifier key function argument */
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
+ { MODKEY, XKB_KEY_b, togglebar, {0} },
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
diff --git a/dwl.c b/dwl.c
index 8a587d1..7a4949b 100644
--- a/dwl.c
+++ b/dwl.c
@@ -68,6 +68,7 @@
#include <xcb/xcb_icccm.h>
#endif
+#include "dwl-ipc-unstable-v2-protocol.h"
#include "util.h"
/* macros */
@@ -144,6 +145,12 @@ typedef struct {
uint32_t resize; /* configure serial of a pending resize */
} Client;
+typedef struct {
+ struct wl_list link;
+ struct wl_resource *resource;
+ Monitor *mon;
+} DwlIpcOutput;
+
typedef struct {
uint32_t mod;
xkb_keysym_t keysym;
@@ -189,6 +196,7 @@ typedef struct {
struct Monitor {
struct wl_list link;
+ struct wl_list dwl_ipc_outputs;
struct wlr_output *wlr_output;
struct wlr_scene_output *scene_output;
struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
@@ -286,6 +294,17 @@ static void destroysessionlock(struct wl_listener *listener, void *data);
static void destroysessionmgr(struct wl_listener *listener, void *data);
static void destroykeyboardgroup(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir);
+static void dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id);
+static void dwl_ipc_manager_destroy(struct wl_resource *resource);
+static void dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output);
+static void dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource);
+static void dwl_ipc_output_destroy(struct wl_resource *resource);
+static void dwl_ipc_output_printstatus(Monitor *monitor);
+static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output);
+static void dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags);
+static void dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index);
+static void dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset);
+static void dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
@@ -338,6 +357,7 @@ static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *m);
+static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
@@ -411,6 +431,9 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = {.release = dwl_ipc_manager_release, .get_output = dwl_ipc_manager_get_output};
+static struct zdwl_ipc_output_v2_interface dwl_output_implementation = {.release = dwl_ipc_output_release, .set_tags = dwl_ipc_output_set_tags, .set_layout = dwl_ipc_output_set_layout, .set_client_tags = dwl_ipc_output_set_client_tags};
+
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
@@ -703,6 +726,10 @@ cleanupmon(struct wl_listener *listener, void *data)
LayerSurface *l, *tmp;
size_t i;
+ DwlIpcOutput *ipc_output, *ipc_output_tmp;
+ wl_list_for_each_safe(ipc_output, ipc_output_tmp, &m->dwl_ipc_outputs, link)
+ wl_resource_destroy(ipc_output->resource);
+
/* m->layers[i] are intentionally not unlinked */
for (i = 0; i < LENGTH(m->layers); i++) {
wl_list_for_each_safe(l, tmp, &m->layers[i], link)
@@ -983,6 +1010,8 @@ createmon(struct wl_listener *listener, void *data)
m = wlr_output->data = ecalloc(1, sizeof(*m));
m->wlr_output = wlr_output;
+ wl_list_init(&m->dwl_ipc_outputs);
+
for (i = 0; i < LENGTH(m->layers); i++)
wl_list_init(&m->layers[i]);
@@ -1334,6 +1363,192 @@ dirtomon(enum wlr_direction dir)
return selmon;
}
+void
+dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *manager_resource = wl_resource_create(client, &zdwl_ipc_manager_v2_interface, version, id);
+ if (!manager_resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+ wl_resource_set_implementation(manager_resource, &dwl_manager_implementation, NULL, dwl_ipc_manager_destroy);
+
+ zdwl_ipc_manager_v2_send_tags(manager_resource, TAGCOUNT);
+
+ for (unsigned int i = 0; i < LENGTH(layouts); i++)
+ zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol);
+}
+
+void
+dwl_ipc_manager_destroy(struct wl_resource *resource)
+{
+ /* No state to destroy */
+}
+
+void
+dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output)
+{
+ DwlIpcOutput *ipc_output;
+ Monitor *monitor = wlr_output_from_resource(output)->data;
+ struct wl_resource *output_resource = wl_resource_create(client, &zdwl_ipc_output_v2_interface, wl_resource_get_version(resource), id);
+ if (!output_resource)
+ return;
+
+ ipc_output = ecalloc(1, sizeof(*ipc_output));
+ ipc_output->resource = output_resource;
+ ipc_output->mon = monitor;
+ wl_resource_set_implementation(output_resource, &dwl_output_implementation, ipc_output, dwl_ipc_output_destroy);
+ wl_list_insert(&monitor->dwl_ipc_outputs, &ipc_output->link);
+ dwl_ipc_output_printstatus_to(ipc_output);
+}
+
+void
+dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+dwl_ipc_output_destroy(struct wl_resource *resource)
+{
+ DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource);
+ wl_list_remove(&ipc_output->link);
+ free(ipc_output);
+}
+
+void
+dwl_ipc_output_printstatus(Monitor *monitor)
+{
+ DwlIpcOutput *ipc_output;
+ wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link)
+ dwl_ipc_output_printstatus_to(ipc_output);
+}
+
+void
+dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output)
+{
+ Monitor *monitor = ipc_output->mon;
+ Client *c, *focused;
+ int tagmask, state, numclients, focused_client, tag;
+ const char *title, *appid;
+ focused = focustop(monitor);
+ zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon);
+
+ for (tag = 0 ; tag < TAGCOUNT; tag++) {
+ numclients = state = focused_client = 0;
+ tagmask = 1 << tag;
+ if ((tagmask & monitor->tagset[monitor->seltags]) != 0)
+ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE;
+
+ wl_list_for_each(c, &clients, link) {
+ if (c->mon != monitor)
+ continue;
+ if (!(c->tags & tagmask))
+ continue;
+ if (c == focused)
+ focused_client = 1;
+ if (c->isurgent)
+ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT;
+
+ numclients++;
+ }
+ zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, numclients, focused_client);
+ }
+ title = focused ? client_get_title(focused) : "";
+ appid = focused ? client_get_appid(focused) : "";
+
+ zdwl_ipc_output_v2_send_layout(ipc_output->resource, monitor->lt[monitor->sellt] - layouts);
+ zdwl_ipc_output_v2_send_title(ipc_output->resource, title);
+ zdwl_ipc_output_v2_send_appid(ipc_output->resource, appid);
+ zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, monitor->ltsymbol);
+ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) {
+ zdwl_ipc_output_v2_send_fullscreen(ipc_output->resource, focused ? focused->isfullscreen : 0);
+ }
+ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) {
+ zdwl_ipc_output_v2_send_floating(ipc_output->resource, focused ? focused->isfloating : 0);
+ }
+ zdwl_ipc_output_v2_send_frame(ipc_output->resource);
+}
+
+void
+dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags)
+{
+ DwlIpcOutput *ipc_output;
+ Monitor *monitor;
+ Client *selected_client;
+ unsigned int newtags = 0;
+
+ ipc_output = wl_resource_get_user_data(resource);
+ if (!ipc_output)
+ return;
+
+ monitor = ipc_output->mon;
+ selected_client = focustop(monitor);
+ if (!selected_client)
+ return;
+
+ newtags = (selected_client->tags & and_tags) ^ xor_tags;
+ if (!newtags)
+ return;
+
+ selected_client->tags = newtags;
+ if (selmon == monitor)
+ focusclient(focustop(monitor), 1);
+ arrange(selmon);
+ printstatus();
+}
+
+void
+dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index)
+{
+ DwlIpcOutput *ipc_output;
+ Monitor *monitor;
+
+ ipc_output = wl_resource_get_user_data(resource);
+ if (!ipc_output)
+ return;
+
+ monitor = ipc_output->mon;
+ if (index >= LENGTH(layouts))
+ return;
+ if (index != monitor->lt[monitor->sellt] - layouts)
+ monitor->sellt ^= 1;
+
+ monitor->lt[monitor->sellt] = &layouts[index];
+ arrange(monitor);
+ printstatus();
+}
+
+void
+dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset)
+{
+ DwlIpcOutput *ipc_output;
+ Monitor *monitor;
+ unsigned int newtags = tagmask & TAGMASK;
+
+ ipc_output = wl_resource_get_user_data(resource);
+ if (!ipc_output)
+ return;
+ monitor = ipc_output->mon;
+
+ if (!newtags || newtags == monitor->tagset[monitor->seltags])
+ return;
+ if (toggle_tagset)
+ monitor->seltags ^= 1;
+
+ monitor->tagset[monitor->seltags] = newtags;
+ if (selmon == monitor)
+ focusclient(focustop(monitor), 1);
+ arrange(monitor);
+ printstatus();
+}
+
+void
+dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
void
focusclient(Client *c, int lift)
{
@@ -2033,38 +2248,9 @@ void
printstatus(void)
{
Monitor *m = NULL;
- Client *c;
- uint32_t occ, urg, sel;
- wl_list_for_each(m, &mons, link) {
- occ = urg = 0;
- wl_list_for_each(c, &clients, link) {
- if (c->mon != m)
- continue;
- occ |= c->tags;
- if (c->isurgent)
- urg |= c->tags;
- }
- if ((c = focustop(m))) {
- printf("%s title %s\n", m->wlr_output->name, client_get_title(c));
- printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c));
- printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen);
- printf("%s floating %d\n", m->wlr_output->name, c->isfloating);
- sel = c->tags;
- } else {
- printf("%s title \n", m->wlr_output->name);
- printf("%s appid \n", m->wlr_output->name);
- printf("%s fullscreen \n", m->wlr_output->name);
- printf("%s floating \n", m->wlr_output->name);
- sel = 0;
- }
-
- printf("%s selmon %u\n", m->wlr_output->name, m == selmon);
- printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n",
- m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg);
- printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol);
- }
- fflush(stdout);
+ wl_list_for_each(m, &mons, link)
+ dwl_ipc_output_printstatus(m);
}
void
@@ -2584,6 +2770,8 @@ setup(void)
LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);
LISTEN_STATIC(&output_mgr->events.test, outputmgrtest);
+ wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind);
+
/* Make sure XWayland clients don't connect to the parent X server,
* e.g when running in the x11 backend or the wayland backend and the
* compositor has Xwayland support */
@@ -2681,6 +2869,13 @@ tile(Monitor *m)
}
}
+void
+togglebar(const Arg *arg) {
+ DwlIpcOutput *ipc_output;
+ wl_list_for_each(ipc_output, &selmon->dwl_ipc_outputs, link)
+ zdwl_ipc_output_v2_send_toggle_visibility(ipc_output->resource);
+}
+
void
togglefloating(const Arg *arg)
{
diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml
new file mode 100644
index 0000000..0a6e7e5
--- /dev/null
+++ b/protocols/dwl-ipc-unstable-v2.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This is largely ripped from somebar's ipc patchset; just with some personal modifications.
+I would probably just submit raphi's patchset but I don't think that would be polite.
+-->
+<protocol name="dwl_ipc_unstable_v2">
+ <description summary="inter-proccess-communication about dwl's state">
+ This protocol allows clients to update and get updates from dwl.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible
+ changes may be added together with the corresponding interface
+ version bump.
+ Backward incompatible changes are done by bumping the version
+ number in the protocol and interface names and resetting the
+ interface version. Once the protocol is to be declared stable,
+ the 'z' prefix and the version number in the protocol and
+ interface names are removed and the interface version number is
+ reset.
+ </description>
+
+ <interface name="zdwl_ipc_manager_v2" version="2">
+ <description summary="manage dwl state">
+ This interface is exposed as a global in wl_registry.
+
+ Clients can use this interface to get a dwl_ipc_output.
+ After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
+ The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
+ </description>
+
+ <request name="release" type="destructor">
+ <description summary="release dwl_ipc_manager">
+ Indicates that the client will not the dwl_ipc_manager object anymore.
+ Objects created through this instance are not affected.
+ </description>
+ </request>
+
+ <request name="get_output">
+ <description summary="get a dwl_ipc_outout for a wl_output">
+ Get a dwl_ipc_outout for the specified wl_output.
+ </description>
+ <arg name="id" type="new_id" interface="zdwl_ipc_output_v2"/>
+ <arg name="output" type="object" interface="wl_output"/>
+ </request>
+
+ <event name="tags">
+ <description summary="Announces tag amount">
+ This event is sent after binding.
+ A roundtrip after binding guarantees the client recieved all tags.
+ </description>
+ <arg name="amount" type="uint"/>
+ </event>
+
+ <event name="layout">
+ <description summary="Announces a layout">
+ This event is sent after binding.
+ A roundtrip after binding guarantees the client recieved all layouts.
+ </description>
+ <arg name="name" type="string"/>
+ </event>
+ </interface>
+
+ <interface name="zdwl_ipc_output_v2" version="2">
+ <description summary="control dwl output">
+ Observe and control a dwl output.
+
+ Events are double-buffered:
+ Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
+
+ Request are not double-buffered:
+ The compositor will update immediately upon request.
+ </description>
+
+ <enum name="tag_state">
+ <entry name="none" value="0" summary="no state"/>
+ <entry name="active" value="1" summary="tag is active"/>
+ <entry name="urgent" value="2" summary="tag has at least one urgent client"/>
+ </enum>
+
+ <request name="release" type="destructor">
+ <description summary="release dwl_ipc_outout">
+ Indicates to that the client no longer needs this dwl_ipc_output.
+ </description>
+ </request>
+
+ <event name="toggle_visibility">
+ <description summary="Toggle client visibilty">
+ Indicates the client should hide or show themselves.
+ If the client is visible then hide, if hidden then show.
+ </description>
+ </event>
+
+ <event name="active">
+ <description summary="Update the selected output.">
+ Indicates if the output is active. Zero is invalid, nonzero is valid.
+ </description>
+ <arg name="active" type="uint"/>
+ </event>
+
+ <event name="tag">
+ <description summary="Update the state of a tag.">
+ Indicates that a tag has been updated.
+ </description>
+ <arg name="tag" type="uint" summary="Index of the tag"/>
+ <arg name="state" type="uint" enum="tag_state" summary="The state of the tag."/>
+ <arg name="clients" type="uint" summary="The number of clients in the tag."/>
+ <arg name="focused" type="uint" summary="If there is a focused client. Nonzero being valid, zero being invalid."/>
+ </event>
+
+ <event name="layout">
+ <description summary="Update the layout.">
+ Indicates a new layout is selected.
+ </description>
+ <arg name="layout" type="uint" summary="Index of the layout."/>
+ </event>
+
+ <event name="title">
+ <description summary="Update the title.">
+ Indicates the title has changed.
+ </description>
+ <arg name="title" type="string" summary="The new title name."/>
+ </event>
+
+ <event name="appid" since="1">
+ <description summary="Update the appid.">
+ Indicates the appid has changed.
+ </description>
+ <arg name="appid" type="string" summary="The new appid."/>
+ </event>
+
+ <event name="layout_symbol" since="1">
+ <description summary="Update the current layout symbol">
+ Indicates the layout has changed. Since layout symbols are dynamic.
+ As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying.
+ You can ignore the zdwl_ipc_output.layout event.
+ </description>
+ <arg name="layout" type="string" summary="The new layout"/>
+ </event>
+
+ <event name="frame">
+ <description summary="The update sequence is done.">
+ Indicates that a sequence of status updates have finished and the client should redraw.
+ </description>
+ </event>
+
+ <request name="set_tags">
+ <description summary="Set the active tags of this output"/>
+ <arg name="tagmask" type="uint" summary="bitmask of the tags that should be set."/>
+ <arg name="toggle_tagset" type="uint" summary="toggle the selected tagset, zero for invalid, nonzero for valid."/>
+ </request>
+
+ <request name="set_client_tags">
+ <description summary="Set the tags of the focused client.">
+ The tags are updated as follows:
+ new_tags = (current_tags AND and_tags) XOR xor_tags
+ </description>
+ <arg name="and_tags" type="uint"/>
+ <arg name="xor_tags" type="uint"/>
+ </request>
+
+ <request name="set_layout">
+ <description summary="Set the layout of this output"/>
+ <arg name="index" type="uint" summary="index of a layout recieved by dwl_ipc_manager.layout"/>
+ </request>
+
+ <!-- Version 2 -->
+ <event name="fullscreen" since="2">
+ <description summary="Update fullscreen status">
+ Indicates if the selected client on this output is fullscreen.
+ </description>
+ <arg name="is_fullscreen" type="uint" summary="If the selected client is fullscreen. Nonzero is valid, zero invalid"/>
+ </event>
+
+ <event name="floating" since="2">
+ <description summary="Update the floating status">
+ Indicates if the selected client on this output is floating.
+ </description>
+ <arg name="is_floating" type="uint" summary="If the selected client is floating. Nonzero is valid, zero invalid"/>
+ </event>
+ </interface>
+</protocol>
--
2.43.0

View File

@@ -0,0 +1,181 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This is largely ripped from somebar's ipc patchset; just with some personal modifications.
I would probably just submit raphi's patchset but I don't think that would be polite.
-->
<protocol name="dwl_ipc_unstable_v2">
<description summary="inter-proccess-communication about dwl's state">
This protocol allows clients to update and get updates from dwl.
Warning! The protocol described in this file is experimental and
backward incompatible changes may be made. Backward compatible
changes may be added together with the corresponding interface
version bump.
Backward incompatible changes are done by bumping the version
number in the protocol and interface names and resetting the
interface version. Once the protocol is to be declared stable,
the 'z' prefix and the version number in the protocol and
interface names are removed and the interface version number is
reset.
</description>
<interface name="zdwl_ipc_manager_v2" version="2">
<description summary="manage dwl state">
This interface is exposed as a global in wl_registry.
Clients can use this interface to get a dwl_ipc_output.
After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
</description>
<request name="release" type="destructor">
<description summary="release dwl_ipc_manager">
Indicates that the client will not the dwl_ipc_manager object anymore.
Objects created through this instance are not affected.
</description>
</request>
<request name="get_output">
<description summary="get a dwl_ipc_outout for a wl_output">
Get a dwl_ipc_outout for the specified wl_output.
</description>
<arg name="id" type="new_id" interface="zdwl_ipc_output_v2"/>
<arg name="output" type="object" interface="wl_output"/>
</request>
<event name="tags">
<description summary="Announces tag amount">
This event is sent after binding.
A roundtrip after binding guarantees the client recieved all tags.
</description>
<arg name="amount" type="uint"/>
</event>
<event name="layout">
<description summary="Announces a layout">
This event is sent after binding.
A roundtrip after binding guarantees the client recieved all layouts.
</description>
<arg name="name" type="string"/>
</event>
</interface>
<interface name="zdwl_ipc_output_v2" version="2">
<description summary="control dwl output">
Observe and control a dwl output.
Events are double-buffered:
Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
Request are not double-buffered:
The compositor will update immediately upon request.
</description>
<enum name="tag_state">
<entry name="none" value="0" summary="no state"/>
<entry name="active" value="1" summary="tag is active"/>
<entry name="urgent" value="2" summary="tag has at least one urgent client"/>
</enum>
<request name="release" type="destructor">
<description summary="release dwl_ipc_outout">
Indicates to that the client no longer needs this dwl_ipc_output.
</description>
</request>
<event name="toggle_visibility">
<description summary="Toggle client visibilty">
Indicates the client should hide or show themselves.
If the client is visible then hide, if hidden then show.
</description>
</event>
<event name="active">
<description summary="Update the selected output.">
Indicates if the output is active. Zero is invalid, nonzero is valid.
</description>
<arg name="active" type="uint"/>
</event>
<event name="tag">
<description summary="Update the state of a tag.">
Indicates that a tag has been updated.
</description>
<arg name="tag" type="uint" summary="Index of the tag"/>
<arg name="state" type="uint" enum="tag_state" summary="The state of the tag."/>
<arg name="clients" type="uint" summary="The number of clients in the tag."/>
<arg name="focused" type="uint" summary="If there is a focused client. Nonzero being valid, zero being invalid."/>
</event>
<event name="layout">
<description summary="Update the layout.">
Indicates a new layout is selected.
</description>
<arg name="layout" type="uint" summary="Index of the layout."/>
</event>
<event name="title">
<description summary="Update the title.">
Indicates the title has changed.
</description>
<arg name="title" type="string" summary="The new title name."/>
</event>
<event name="appid" since="1">
<description summary="Update the appid.">
Indicates the appid has changed.
</description>
<arg name="appid" type="string" summary="The new appid."/>
</event>
<event name="layout_symbol" since="1">
<description summary="Update the current layout symbol">
Indicates the layout has changed. Since layout symbols are dynamic.
As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying.
You can ignore the zdwl_ipc_output.layout event.
</description>
<arg name="layout" type="string" summary="The new layout"/>
</event>
<event name="frame">
<description summary="The update sequence is done.">
Indicates that a sequence of status updates have finished and the client should redraw.
</description>
</event>
<request name="set_tags">
<description summary="Set the active tags of this output"/>
<arg name="tagmask" type="uint" summary="bitmask of the tags that should be set."/>
<arg name="toggle_tagset" type="uint" summary="toggle the selected tagset, zero for invalid, nonzero for valid."/>
</request>
<request name="set_client_tags">
<description summary="Set the tags of the focused client.">
The tags are updated as follows:
new_tags = (current_tags AND and_tags) XOR xor_tags
</description>
<arg name="and_tags" type="uint"/>
<arg name="xor_tags" type="uint"/>
</request>
<request name="set_layout">
<description summary="Set the layout of this output"/>
<arg name="index" type="uint" summary="index of a layout recieved by dwl_ipc_manager.layout"/>
</request>
<!-- Version 2 -->
<event name="fullscreen" since="2">
<description summary="Update fullscreen status">
Indicates if the selected client on this output is fullscreen.
</description>
<arg name="is_fullscreen" type="uint" summary="If the selected client is fullscreen. Nonzero is valid, zero invalid"/>
</event>
<event name="floating" since="2">
<description summary="Update the floating status">
Indicates if the selected client on this output is floating.
</description>
<arg name="is_floating" type="uint" summary="If the selected client is floating. Nonzero is valid, zero invalid"/>
</event>
</interface>
</protocol>