aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile14
-rw-r--r--README.md9
-rw-r--r--config.def.h7
-rw-r--r--dwlb.c445
-rw-r--r--protocols/net-tapesoftware-dwl-wm-unstable-v1.xml164
6 files changed, 501 insertions, 140 deletions
diff --git a/.gitignore b/.gitignore
index 9d5528d..79e08a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,5 @@ xdg-shell-protocol.c
xdg-shell-protocol.h
xdg-output-unstable-v1-protocol.c
xdg-output-unstable-v1-protocol.h
+net-tapesoftware-dwl-wm-unstable-v1-protocol.c
+net-tapesoftware-dwl-wm-unstable-v1-protocol.h
diff --git a/Makefile b/Makefile
index 3e5a145..227faa9 100644
--- a/Makefile
+++ b/Makefile
@@ -47,10 +47,20 @@ wlr-layer-shell-unstable-v1-protocol.c:
wlr-layer-shell-unstable-v1-protocol.o: wlr-layer-shell-unstable-v1-protocol.h
-dwlb.o: utf8.h config.h xdg-shell-protocol.h xdg-output-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h
+net-tapesoftware-dwl-wm-unstable-v1-protocol.h:
+ $(WAYLAND_SCANNER) client-header \
+ protocols/net-tapesoftware-dwl-wm-unstable-v1.xml $@
+
+net-tapesoftware-dwl-wm-unstable-v1-protocol.c:
+ $(WAYLAND_SCANNER) private-code \
+ protocols/net-tapesoftware-dwl-wm-unstable-v1.xml $@
+
+net-tapesoftware-dwl-wm-unstable-v1-protocol.o: net-tapesoftware-dwl-wm-unstable-v1-protocol.h
+
+dwlb.o: utf8.h config.h xdg-shell-protocol.h xdg-output-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h net-tapesoftware-dwl-wm-unstable-v1-protocol.o
# Protocol dependencies
-dwlb: xdg-shell-protocol.o xdg-output-unstable-v1-protocol.o wlr-layer-shell-unstable-v1-protocol.o
+dwlb: xdg-shell-protocol.o xdg-output-unstable-v1-protocol.o wlr-layer-shell-unstable-v1-protocol.o net-tapesoftware-dwl-wm-unstable-v1-protocol.o
# Library dependencies
dwlb: CFLAGS+=$(shell pkg-config --cflags wayland-client wayland-cursor fcft pixman-1)
diff --git a/README.md b/README.md
index 20f32a3..2cdfa67 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
![screenshot 1](/screenshot1.png "screenshot 1")
![screenshot 2](/screenshot2.png "screenshot 2")
-dwlb is a simple bar for [dwl](https://github.com/djpohly/dwl). It is a modified version of [dtao](https://github.com/djpohly/dtao).
+dwlb is a feature-complete bar for [dwl](https://github.com/djpohly/dwl).
## Dependencies
* libwayland-client
@@ -26,6 +26,9 @@ Pass `dwlb` as an argument to dwl's `-s` flag. This will populate each connected
dwl -s 'dwlb -font "monospace:size=16"'
```
+## Ipc
+If dwl is patched appropriately, dwlb is capable of communicating directly with dwl. When ipc is enabled with `-ipc`, dwlb does not read from stdin, and clicking tags functions as you would expect. Ipc can be disabled with `-no-ipc`.
+
## Commands
Command options send instructions to existing instances of dwlb. All commands take at least one argument to specify a bar on which to operate. This may be zxdg_output_v1 name, "all" to affect all outputs, "selected" for the current output, or "first" for the first output in the internal list.
@@ -44,3 +47,7 @@ A color command with no argument reverts to the default value. `^^` represents a
## Other Options
Run `dwlb -h` for a full list of options.
+
+## Acknowledgements
+* [dtao](https://github.com/djpohly/dtao)
+* [somebar](https://sr.ht/~raphi/somebar/)
diff --git a/config.def.h b/config.def.h
index b641618..1a002e8 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,3 +1,6 @@
+// use ipc functionality
+static bool ipc = false;
+
// bar properties
static bool hidden = false;
static bool bottom = false;
@@ -6,8 +9,8 @@ static bool hide_vacant = false;
// font
static char *fontstr = "monospace:size=10";
-// tag names
-static char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+// tag names if ipc is disabled
+static char *tags_noipc[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
// set 16-bit colors for bar
// 8-bit color can be converted to 16-bit color by simply duplicating values e.g
diff --git a/dwlb.c b/dwlb.c
index 93b8fe0..ebeb991 100644
--- a/dwlb.c
+++ b/dwlb.c
@@ -25,8 +25,9 @@
#include "xdg-shell-protocol.h"
#include "xdg-output-unstable-v1-protocol.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
+#include "net-tapesoftware-dwl-wm-unstable-v1-protocol.h"
-#define DIE(fmt, ...) \
+#define DIE(fmt, ...) \
do { \
cleanup(); \
fprintf(stderr, fmt "\n", ##__VA_ARGS__); \
@@ -42,7 +43,7 @@
#define LENGTH(x) \
(sizeof x / sizeof x[0])
-#define ARRAY_INIT_CAP 8
+#define ARRAY_INIT_CAP 16
#define ARRAY_EXPAND(arr, len, cap, inc) \
do { \
uint32_t new_len, new_cap; \
@@ -52,7 +53,7 @@
if (new_cap < ARRAY_INIT_CAP) \
new_cap = ARRAY_INIT_CAP; \
if (!((arr) = realloc((arr), sizeof(*(arr)) * new_cap))) \
- EDIE("realloc"); \
+ EDIE("realloc"); \
(cap) = new_cap; \
} \
(len) = new_len; \
@@ -67,6 +68,9 @@
#define VERSION "0.1"
#define USAGE \
"usage: dwlb [OPTIONS]\n" \
+ "Ipc\n" \
+ " -ipc allow commands to be sent to dwl (dwl must be patched)\n" \
+ " -no-ipc disable ipc\n" \
"Bar Config\n" \
" -hidden bars will initially be hidden\n" \
" -no-hidden bars will not initially be hidden\n" \
@@ -104,13 +108,10 @@ typedef struct {
} StatusColor;
typedef struct {
- uint32_t button;
+ uint32_t btn;
uint32_t x1;
uint32_t x2;
- bool incomplete;
char command[128];
- char *start;
- char *end;
} StatusButton;
typedef struct Bar Bar;
@@ -119,6 +120,7 @@ struct Bar {
struct wl_output *wl_output;
struct wl_surface *wl_surface;
struct zwlr_layer_surface_v1 *layer_surface;
+ struct znet_tapesoftware_dwl_wm_monitor_v1 *dwl_wm_monitor;
uint32_t registry_name;
char *xdg_output_name;
@@ -135,7 +137,9 @@ struct Bar {
uint32_t urg;
uint32_t selmon;
char layout[32];
- char title[512];
+ uint32_t layout_idx;
+ uint32_t last_layout_idx;
+ char title[1024];
char status[1024];
StatusColor *status_colors;
@@ -158,7 +162,7 @@ struct Seat {
uint32_t registry_name;
- Bar *pointer_bar;
+ Bar *bar;
uint32_t pointer_x;
uint32_t pointer_y;
uint32_t pointer_button;
@@ -170,6 +174,7 @@ static int sock_fd;
static char socketdir[256];
static char *socketpath = NULL;
static char sockbuf[768];
+
static char *stdinbuf;
static size_t stdinbuf_cap;
@@ -180,12 +185,17 @@ static struct zwlr_layer_shell_v1 *layer_shell;
static struct zxdg_output_manager_v1 *output_manager;
static struct wl_cursor_image *cursor_image;
static struct wl_surface *cursor_surface;
+static struct znet_tapesoftware_dwl_wm_v1 *dwl_wm;
+
+static char **tags = NULL;
+static uint32_t tags_l, tags_c;
+static char **layouts = NULL;
+static uint32_t layouts_l, layouts_c;
static Bar *bar_list = NULL;
static Seat *seat_list = NULL;
static struct fcft_font *font;
-
static uint32_t height;
static uint32_t textpadding;
@@ -225,29 +235,27 @@ allocate_shm_file(size_t size)
static uint32_t
draw_text(char *text,
- uint32_t xpos,
- uint32_t ypos,
+ uint32_t x,
+ uint32_t y,
pixman_image_t *foreground,
pixman_image_t *background,
pixman_color_t *fg_color,
pixman_color_t *bg_color,
- uint32_t max_xpos,
+ uint32_t max_x,
uint32_t buf_height,
uint32_t padding,
StatusColor *colors,
- uint32_t colors_l,
- StatusButton *buttons,
- uint32_t buttons_l)
+ uint32_t colors_l)
{
- if (!*text || !max_xpos)
- return xpos;
+ if (!*text || !max_x)
+ return x;
- uint32_t ixpos = xpos;
- uint32_t nxpos;
+ uint32_t ix = x;
+ uint32_t nx;
- if ((nxpos = xpos + padding) + padding >= max_xpos)
- return xpos;
- xpos = nxpos;
+ if ((nx = x + padding) + padding >= max_x)
+ return x;
+ x = nx;
bool draw_fg = foreground && fg_color;
bool draw_bg = background && bg_color;
@@ -259,41 +267,25 @@ draw_text(char *text,
if (draw_bg)
cur_bg_color = bg_color;
- if (buttons)
- for (uint32_t i = 0; i < buttons_l; i++)
- buttons[i].incomplete = true;
-
+ uint32_t color_ind = 0;
uint32_t codepoint;
uint32_t state = UTF8_ACCEPT;
uint32_t last_cp = 0;
- uint32_t color_ind = 0;
for (char *p = text; *p; p++) {
- if (state == UTF8_ACCEPT) {
- if (colors && (draw_fg || draw_bg)) {
- while (color_ind < colors_l && p == colors[color_ind].start) {
- if (colors[color_ind].bg) {
- if (draw_bg)
- cur_bg_color = &colors[color_ind].color;
- } else {
- if (draw_fg) {
- pixman_image_unref(fg_fill);
- fg_fill = pixman_image_create_solid_fill(&colors[color_ind].color);
- }
- }
- color_ind++;
- }
- }
-
- if (buttons) {
- for (uint32_t i = 0; i < buttons_l; i++) {
- if (p == buttons[i].start) {
- buttons[i].x1 = xpos;
- } else if (p == buttons[i].end) {
- buttons[i].x2 = xpos;
- buttons[i].incomplete = false;
+ /* Check for new colors */
+ if (state == UTF8_ACCEPT && colors && (draw_fg || draw_bg)) {
+ while (color_ind < colors_l && p == colors[color_ind].start) {
+ if (colors[color_ind].bg) {
+ if (draw_bg)
+ cur_bg_color = &colors[color_ind].color;
+ } else {
+ if (draw_fg) {
+ pixman_image_unref(fg_fill);
+ fg_fill = pixman_image_create_solid_fill(&colors[color_ind].color);
}
}
+ color_ind++;
}
}
@@ -308,13 +300,13 @@ draw_text(char *text,
continue;
/* Adjust x position based on kerning with previous glyph */
- long x_kern = 0;
+ long kern = 0;
if (last_cp)
- fcft_kerning(font, last_cp, codepoint, &x_kern, NULL);
- if ((nxpos = xpos + x_kern + glyph->advance.x) + padding > max_xpos)
+ fcft_kerning(font, last_cp, codepoint, &kern, NULL);
+ if ((nx = x + kern + glyph->advance.x) + padding > max_x)
break;
last_cp = codepoint;
- xpos += x_kern;
+ x += kern;
if (draw_fg) {
/* Detect and handle pre-rendered glyphs (e.g. emoji) */
@@ -324,58 +316,53 @@ draw_text(char *text,
* same opacity */
pixman_image_composite32(
PIXMAN_OP_OVER, glyph->pix, fg_fill, foreground, 0, 0, 0, 0,
- xpos + glyph->x, ypos - glyph->y, glyph->width, glyph->height);
+ x + glyph->x, y - glyph->y, glyph->width, glyph->height);
} else {
/* Applying the foreground color here would mess up
* component alphas for subpixel-rendered text, so we
* apply it when blending. */
pixman_image_composite32(
PIXMAN_OP_OVER, fg_fill, glyph->pix, foreground, 0, 0, 0, 0,
- xpos + glyph->x, ypos - glyph->y, glyph->width, glyph->height);
+ x + glyph->x, y - glyph->y, glyph->width, glyph->height);
}
}
if (draw_bg)
pixman_image_fill_boxes(PIXMAN_OP_OVER, background,
cur_bg_color, 1, &(pixman_box32_t){
- .x1 = xpos, .x2 = nxpos,
+ .x1 = x, .x2 = nx,
.y1 = 0, .y2 = buf_height
});
/* increment pen position */
- xpos = nxpos;
- ypos += glyph->advance.y;
+ x = nx;
}
if (draw_fg)
pixman_image_unref(fg_fill);
- if (buttons)
- for (uint32_t i = 0; i < buttons_l; i++)
- if (buttons[i].incomplete)
- buttons[i].x2 = last_cp ? xpos : ixpos;
if (!last_cp)
- return ixpos;
+ return ix;
- nxpos = xpos + padding;
+ nx = x + padding;
if (draw_bg) {
/* Fill padding background */
pixman_image_fill_boxes(PIXMAN_OP_OVER, background,
bg_color, 1, &(pixman_box32_t){
- .x1 = ixpos, .x2 = ixpos + padding,
+ .x1 = ix, .x2 = ix + padding,
.y1 = 0, .y2 = buf_height
});
pixman_image_fill_boxes(PIXMAN_OP_OVER, background,
bg_color, 1, &(pixman_box32_t){
- .x1 = xpos, .x2 = nxpos,
+ .x1 = x, .x2 = nx,
.y1 = 0, .y2 = buf_height
});
}
- return nxpos;
+ return nx;
}
#define TEXT_WIDTH(text, maxwidth, padding) \
- draw_text(text, 0, 0, NULL, NULL, NULL, NULL, maxwidth, 0, padding, NULL, 0, NULL, 0)
+ draw_text(text, 0, 0, NULL, NULL, NULL, NULL, maxwidth, 0, padding, NULL, 0)
static int
draw_frame(Bar *bar)
@@ -405,54 +392,52 @@ draw_frame(Bar *bar)
pixman_image_t *background = pixman_image_create_bits(PIXMAN_a8r8g8b8, bar->width, bar->height, NULL, bar->width * 4);
/* Draw on images */
- uint32_t xpos_left = 0;
- uint32_t ypos = (bar->height + font->ascent - font->descent) / 2;
+ uint32_t x = 0;
+ uint32_t y = (bar->height + font->ascent - font->descent) / 2;
uint32_t boxs = font->height / 9;
uint32_t boxw = font->height / 6 + 2;
- for (uint32_t i = 0; i < LENGTH(tags); i++) {
+ for (uint32_t i = 0; i < tags_l; i++) {
bool active = bar->mtags & 1 << i;
bool occupied = bar->ctags & 1 << i;
bool urgent = bar->urg & 1 << i;
-
if (hide_vacant && !active && !occupied && !urgent)
continue;
pixman_color_t *fg_color = urgent ? &urgent_fg_color : (active ? &active_fg_color : &inactive_fg_color);
pixman_color_t *bg_color = urgent ? &urgent_bg_color : (active ? &active_bg_color : &inactive_bg_color);
-
+
if (!hide_vacant && occupied)
pixman_image_fill_boxes(PIXMAN_OP_SRC, foreground,
fg_color, 1, &(pixman_box32_t){
- .x1 = xpos_left + boxs, .x2 = xpos_left + boxs + boxw,
+ .x1 = x + boxs, .x2 = x + boxs + boxw,
.y1 = boxs, .y2 = boxs + boxw
});
- xpos_left = draw_text(tags[i], xpos_left, ypos, foreground, background, fg_color, bg_color,
- bar->width, bar->height, bar->textpadding, NULL, 0, NULL, 0);
+ x = draw_text(tags[i], x, y, foreground, background, fg_color, bg_color,
+ bar->width, bar->height, bar->textpadding, NULL, 0);
}
- xpos_left = draw_text(bar->layout, xpos_left, ypos, foreground, background,
- &inactive_fg_color, &inactive_bg_color, bar->width,
- bar->height, bar->textpadding, NULL, 0, NULL, 0);
-
- uint32_t status_width = TEXT_WIDTH(bar->status, bar->width - xpos_left, bar->textpadding);
- draw_text(bar->status, bar->width - status_width, ypos, foreground,
+ x = draw_text(bar->layout, x, y, foreground, background,
+ &inactive_fg_color, &inactive_bg_color, bar->width,
+ bar->height, bar->textpadding, NULL, 0);
+
+ uint32_t status_width = TEXT_WIDTH(bar->status, bar->width - x, bar->textpadding);
+ draw_text(bar->status, bar->width - status_width, y, foreground,
background, &inactive_fg_color, &inactive_bg_color,
bar->width, bar->height, bar->textpadding,
- bar->status_colors, bar->status_colors_l,
- bar->status_buttons, bar->status_buttons_l);
+ bar->status_colors, bar->status_colors_l);
- xpos_left = draw_text(bar->title, xpos_left, ypos, foreground, background,
- bar->selmon ? &active_fg_color : &inactive_fg_color,
- bar->selmon ? &active_bg_color : &inactive_bg_color,
- bar->width - status_width, bar->height, bar->textpadding,
- NULL, 0, NULL, 0);
+ x = draw_text(bar->title, x, y, foreground, background,
+ bar->selmon ? &active_fg_color : &inactive_fg_color,
+ bar->selmon ? &active_bg_color : &inactive_bg_color,
+ bar->width - status_width, bar->height, bar->textpadding,
+ NULL, 0);
pixman_image_fill_boxes(PIXMAN_OP_SRC, background,
bar->selmon ? &active_bg_color : &inactive_bg_color, 1,
&(pixman_box32_t){
- .x1 = xpos_left, .x2 = bar->width - status_width,
+ .x1 = x, .x2 = bar->width - status_width,
.y1 = 0, .y2 = bar->height
});
@@ -576,7 +561,7 @@ pointer_enter(void *data, struct wl_pointer *pointer,
DL_FOREACH(bar_list, bar)
if (bar->wl_surface == surface)
break;
- seat->pointer_bar = bar;
+ seat->bar = bar;
if (!cursor_image) {
struct wl_cursor_theme *cursor_theme = wl_cursor_theme_load(NULL, 24, shm);
@@ -596,7 +581,7 @@ pointer_leave(void *data, struct wl_pointer *pointer,
{
Seat *seat = (Seat *)data;
- seat->pointer_bar = NULL;
+ seat->bar = NULL;
}
static void
@@ -623,15 +608,55 @@ pointer_frame(void *data, struct wl_pointer *pointer)
{
Seat *seat = (Seat *)data;
- if (!seat->pointer_button || !seat->pointer_bar)
+ if (!seat->pointer_button || !seat->bar)
return;
- for (uint32_t i = 0; i < seat->pointer_bar->status_buttons_l; i++) {\
- if (seat->pointer_button == seat->pointer_bar->status_buttons[i].button
- && seat->pointer_x >= seat->pointer_bar->status_buttons[i].x1
- && seat->pointer_x < seat->pointer_bar->status_buttons[i].x2) {
- shell_command(seat->pointer_bar->status_buttons[i].command);
- break;
+ uint32_t x = 0;
+ uint32_t i = 0;
+ do {
+ if (hide_vacant) {
+ bool active = seat->bar->mtags & 1 << i;
+ bool occupied = seat->bar->ctags & 1 << i;
+ bool urgent = seat->bar->urg & 1 << i;
+ if (!active && !occupied && !urgent)
+ continue;
+ }
+ x += TEXT_WIDTH(tags[i], seat->bar->width - x, seat->bar->textpadding);
+ } while (seat->pointer_x >= x && ++i < tags_l);
+
+ if (i < tags_l) {
+ /* Clicked on tags */
+ if (ipc) {
+ if (seat->pointer_button == BTN_LEFT)
+ znet_tapesoftware_dwl_wm_monitor_v1_set_tags(seat->bar->dwl_wm_monitor, 1 << i, 1);
+ else if (seat->pointer_button == BTN_MIDDLE)
+ znet_tapesoftware_dwl_wm_monitor_v1_set_tags(seat->bar->dwl_wm_monitor, ~0, 1 << i);
+ else if (seat->pointer_button == BTN_RIGHT)
+ znet_tapesoftware_dwl_wm_monitor_v1_set_tags(seat->bar->dwl_wm_monitor, 0, 1 << i);
+ }
+ } else if (seat->pointer_x < (x += TEXT_WIDTH(seat->bar->layout, seat->bar->width - x, seat->bar->textpadding))) {
+ /* Clicked on layout */
+ if (ipc) {
+ if (seat->pointer_button == BTN_LEFT)
+ znet_tapesoftware_dwl_wm_monitor_v1_set_layout(seat->bar->dwl_wm_monitor, seat->bar->last_layout_idx);
+ else if (seat->pointer_button == BTN_RIGHT)
+ znet_tapesoftware_dwl_wm_monitor_v1_set_layout(seat->bar->dwl_wm_monitor, 2);
+ }
+ } else {
+ uint32_t status_x = seat->bar->width - TEXT_WIDTH(seat->bar->status, seat->bar->width - x, seat->bar->textpadding);
+ if (seat->pointer_x < status_x) {
+ /* Clicked on title */
+
+ } else {
+ /* Clicked on status */
+ for (i = 0; i < seat->bar->status_buttons_l; i++) {
+ if (seat->pointer_button == seat->bar->status_buttons[i].btn
+ && seat->pointer_x >= status_x + seat->bar->textpadding + seat->bar->status_buttons[i].x1
+ && seat->pointer_x < status_x + seat->bar->textpadding + seat->bar->status_buttons[i].x2) {
+ shell_command(seat->bar->status_buttons[i].command);
+ break;
+ }
+ }
}
}
@@ -708,6 +733,107 @@ static const struct wl_seat_listener seat_listener = {
};
static void
+dwl_wm_tag(void *data, struct znet_tapesoftware_dwl_wm_v1 *dwl_wm, const char *name)
+{
+ char **ptr;
+ ARRAY_APPEND(tags, tags_l, tags_c, ptr);
+ if (!(*ptr = strdup(name)))
+ EDIE("strdup");
+}
+
+static void
+dwl_wm_layout(void *data, struct znet_tapesoftware_dwl_wm_v1 *dwl_wm, const char *name)
+{
+ char **ptr;
+ ARRAY_APPEND(layouts, layouts_l, layouts_c, ptr);
+ if (!(*ptr = strdup(name)))
+ EDIE("strdup");
+}
+
+static const struct znet_tapesoftware_dwl_wm_v1_listener dwl_wm_listener = {
+ .tag = dwl_wm_tag,
+ .layout = dwl_wm_layout
+};
+
+static void
+dwl_wm_monitor_selected(void *data, struct znet_tapesoftware_dwl_wm_monitor_v1 *dwl_wm_monitor,
+ uint32_t selected)
+{
+ Bar *bar = (Bar *)data;
+
+ if (selected != bar->selmon) {
+ bar->selmon = selected;
+ bar->redraw = true;
+ }
+}
+
+static void
+dwl_wm_monitor_tag(void *data, struct znet_tapesoftware_dwl_wm_monitor_v1 *dwl_wm_monitor,
+ uint32_t tag, uint32_t state, uint32_t clients, int32_t focused_client)
+{
+ Bar *bar = (Bar *)data;
+
+ uint32_t imtags = bar->mtags;
+ uint32_t ictags = bar->ctags;
+ uint32_t iurg = bar->urg;
+
+ if (state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_ACTIVE)
+ bar->mtags |= 1 << tag;
+ else
+ bar->mtags &= ~(1 << tag);
+ if (clients > 0)
+ bar->ctags |= 1 << tag;
+ else
+ bar->ctags &= ~(1 << tag);
+ if (state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_URGENT)
+ bar->urg |= 1 << tag;
+ else
+ bar->urg &= ~(1 << tag);
+
+ if (bar->mtags != imtags || bar->ctags != ictags || bar->urg != iurg)
+ bar->redraw = true;
+}
+
+static void
+dwl_wm_monitor_layout(void *data, struct znet_tapesoftware_dwl_wm_monitor_v1 *dwl_wm_monitor,
+ uint32_t layout)
+{
+ Bar *bar = (Bar *)data;
+
+ if (strcmp(bar->layout, layouts[layout]) != 0) {
+ snprintf(bar->layout, sizeof bar->layout, "%s", layouts[layout]);
+ bar->last_layout_idx = bar->layout_idx;
+ bar->layout_idx = layout;
+ bar->redraw = true;
+ }
+}
+
+static void
+dwl_wm_monitor_title(void *data, struct znet_tapesoftware_dwl_wm_monitor_v1 *dwl_wm_monitor,
+ const char *title)
+{
+ Bar *bar = (Bar *)data;
+
+ if (strcmp(bar->title, title) != 0) {
+ snprintf(bar->title, sizeof bar->title, "%s", title);
+ bar->redraw = true;
+ }
+}
+
+static void
+dwl_wm_monitor_frame(void *data, struct znet_tapesoftware_dwl_wm_monitor_v1 *dwl_wm_monitor)
+{
+}
+
+static const struct znet_tapesoftware_dwl_wm_monitor_v1_listener dwl_wm_monitor_listener = {
+ .selected = dwl_wm_monitor_selected,
+ .tag = dwl_wm_monitor_tag,
+ .layout = dwl_wm_monitor_layout,
+ .title = dwl_wm_monitor_title,
+ .frame = dwl_wm_monitor_frame
+};
+
+static void
show_bar(Bar *bar)
{
bar->wl_surface = wl_compositor_create_surface(compositor);
@@ -715,7 +841,7 @@ show_bar(Bar *bar)
DIE("Could not create wl_surface");
bar->layer_surface = zwlr_layer_shell_v1_get_layer_surface(layer_shell, bar->wl_surface, bar->wl_output,
- ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, PROGRAM);
+ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, PROGRAM);
if (!bar->layer_surface)
DIE("Could not create layer_surface");
zwlr_layer_surface_v1_add_listener(bar->layer_surface, &layer_surface_listener, bar);
@@ -749,13 +875,21 @@ setup_bar(Bar *bar)
bar->bottom = bottom;
bar->hidden = hidden;
- snprintf(bar->layout, sizeof bar->layout, "[]=");
+ if (!ipc)
+ snprintf(bar->layout, sizeof bar->layout, "[]=");
bar->xdg_output = zxdg_output_manager_v1_get_xdg_output(output_manager, bar->wl_output);
if (!bar->xdg_output)
DIE("Could not create xdg_output");
zxdg_output_v1_add_listener(bar->xdg_output, &output_listener, bar);
+ if (ipc) {
+ bar->dwl_wm_monitor = znet_tapesoftware_dwl_wm_v1_get_monitor(dwl_wm, bar->wl_output);
+ if (!bar->dwl_wm_monitor)
+ DIE("Could not create dwl_wm_monitor");
+ znet_tapesoftware_dwl_wm_monitor_v1_add_listener(bar->dwl_wm_monitor, &dwl_wm_monitor_listener, bar);
+ }
+
if (!bar->hidden)
show_bar(bar);
}
@@ -778,6 +912,11 @@ handle_global(void *data, struct wl_registry *registry,
layer_shell = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1);
} else if (!strcmp(interface, zxdg_output_manager_v1_interface.name)) {
output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, 2);
+ } else if (!strcmp(interface, znet_tapesoftware_dwl_wm_v1_interface.name)) {
+ if (ipc) {
+ dwl_wm = wl_registry_bind(registry, name, &znet_tapesoftware_dwl_wm_v1_interface, 1);
+ znet_tapesoftware_dwl_wm_v1_add_listener(dwl_wm, &dwl_wm_listener, NULL);
+ }
} else if (!strcmp(interface, wl_output_interface.name)) {
Bar *bar = malloc(sizeof(Bar));
if (!bar)
@@ -808,6 +947,8 @@ teardown_bar(Bar *bar)
zwlr_layer_surface_v1_destroy(bar->layer_surface);
wl_surface_destroy(bar->wl_surface);
}
+ if (ipc)
+ znet_tapesoftware_dwl_wm_monitor_v1_destroy(bar->dwl_wm_monitor);
if (bar->xdg_output_name)
free(bar->xdg_output_name);
if (bar->status_colors)
@@ -1012,11 +1153,13 @@ set_status(Bar *bar, char *text)
{
bar->status_colors_l = 0;
bar->status_buttons_l = 0;
-
+
if (status_commands) {
- size_t str_pos = 0;
uint32_t codepoint;
uint32_t state = UTF8_ACCEPT;
+ uint32_t last_cp = 0;
+ uint32_t x = 0;
+ size_t str_pos = 0;
StatusButton *left_button = NULL;
StatusButton *middle_button = NULL;
@@ -1052,33 +1195,33 @@ set_status(Bar *bar, char *text)
status_color->start = bar->status + str_pos;
} else if (!strcmp(p, "lm")) {
if (left_button) {
- left_button->end = bar->status + str_pos;
+ left_button->x2 = x;
left_button = NULL;
} else if (*arg) {
ARRAY_APPEND(bar->status_buttons, bar->status_buttons_l, bar->status_buttons_c, left_button);
- left_button->button = BTN_LEFT;
+ left_button->btn = BTN_LEFT;
snprintf(left_button->command, sizeof left_button->command, "%s", arg);
- left_button->start = bar->status + str_pos;
+ left_button->x1 = x;
}
} else if (!strcmp(p, "mm")) {
if (middle_button) {
- middle_button->end = bar->status + str_pos;
+ middle_button->x2 = x;
middle_button = NULL;
} else if (*arg) {
ARRAY_APPEND(bar->status_buttons, bar->status_buttons_l, bar->status_buttons_c, middle_button);
- middle_button->button = BTN_MIDDLE;
+ middle_button->btn = BTN_MIDDLE;
snprintf(middle_button->command, sizeof middle_button->command, "%s", arg);
- middle_button->start = bar->status + str_pos;
+ middle_button->x1 = x;
}
} else if (!strcmp(p, "rm")) {
if (right_button) {
- right_button->end = bar->status + str_pos;
+ right_button->x2 = x;
right_button = NULL;
} else if (*arg) {
ARRAY_APPEND(bar->status_buttons, bar->status_buttons_l, bar->status_buttons_c, right_button);
- right_button->button = BTN_RIGHT;
+ right_button->btn = BTN_RIGHT;
snprintf(right_button->command, sizeof right_button->command, "%s", arg);
- right_button->start = bar->status + str_pos;
+ right_button->x1 = x;
}
}
@@ -1091,15 +1234,28 @@ set_status(Bar *bar, char *text)
}
bar->status[str_pos++] = *p;
- utf8decode(&state, &codepoint, *p);
+
+ if (utf8decode(&state, &codepoint, *p))
+ continue;
+
+ const struct fcft_glyph *glyph = fcft_rasterize_char_utf32(font, codepoint, FCFT_SUBPIXEL_NONE);
+ if (!glyph)
+ continue;
+
+ long kern = 0;
+ if (last_cp)
+ fcft_kerning(font, last_cp, codepoint, &kern, NULL);
+ last_cp = codepoint;
+
+ x += kern + glyph->advance.x;
}
if (left_button)
- left_button->end = bar->status + str_pos;
+ left_button->x2 = x;
if (middle_button)
- middle_button->end = bar->status + str_pos;
+ middle_button->x2 = x;
if (right_button)
- right_button->end = bar->status + str_pos;
+ right_button->x2 = x;
bar->status[str_pos] = '\0';
} else {
@@ -1239,8 +1395,9 @@ event_loop(void)
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(wl_fd, &rfds);
- FD_SET(STDIN_FILENO, &rfds);
FD_SET(sock_fd, &rfds);
+ if (!ipc)
+ FD_SET(STDIN_FILENO, &rfds);
wl_display_flush(display);
@@ -1254,10 +1411,10 @@ event_loop(void)
if (FD_ISSET(wl_fd, &rfds))
if (wl_display_dispatch(display) == -1)
break;
- if (FD_ISSET(STDIN_FILENO, &rfds))
- read_stdin();
if (FD_ISSET(sock_fd, &rfds))
read_socket();
+ if (!ipc && FD_ISSET(STDIN_FILENO, &rfds))
+ read_stdin();
Bar *bar;
DL_FOREACH(bar_list, bar) {
@@ -1369,6 +1526,10 @@ main(int argc, char **argv)
DIE("Option -toggle-location requires an argument");
client_send_command(&sock_address, argv[i], "toggle-location", NULL);
return 0;
+ } else if (!strcmp(argv[i], "-ipc")) {
+ ipc = true;
+ } else if (!strcmp(argv[i], "-no-ipc")) {
+ ipc = false;
} else if (!strcmp(argv[i], "-hide-vacant-tags")) {
hide_vacant = true;
} else if (!strcmp(argv[i], "-no-hide-vacant-tags")) {
@@ -1424,11 +1585,11 @@ main(int argc, char **argv)
if (parse_color(argv[i], &urgent_bg_color) == -1)
DIE("malformed color string");
} else if (!strcmp(argv[i], "-tags")) {
- if (i + (int)LENGTH(tags) >= argc)
- DIE("Option -tags requires %lu arguments", LENGTH(tags));
- for (int j = 0; j < (int)LENGTH(tags); j++)
+ if (i + (int)LENGTH(tags_noipc) >= argc)
+ DIE("Option -tags requires %lu arguments", LENGTH(tags_noipc));
+ for (int j = 0; j < (int)LENGTH(tags_noipc); j++)
tags[j] = argv[i + 1 + j];
- i += LENGTH(tags);
+ i += LENGTH(tags_noipc);
} else if (!strcmp(argv[i], "-v")) {
fprintf(stderr, PROGRAM " " VERSION "\n");
return 0;
@@ -1448,7 +1609,7 @@ main(int argc, char **argv)
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_roundtrip(display);
- if (!compositor || !shm || !layer_shell || !output_manager)
+ if (!compositor || !shm || !layer_shell || !output_manager || (ipc && !dwl_wm))
DIE("Compositor does not support all needed protocols");
/* Load selected font */
@@ -1459,20 +1620,31 @@ main(int argc, char **argv)
DIE("Could not load font");
textpadding = font->height / 2;
height = font->height + vertical_padding * 2;
-
+
+ if (!ipc) {
+ /* Load in tag names */
+ if (!(tags = malloc(LENGTH(tags_noipc) * sizeof(char *))))
+ EDIE("malloc");
+ tags_l = LENGTH(tags_noipc);
+ for (uint32_t i = 0; i < tags_l; i++)
+ tags[i] = tags_noipc[i];
+ }
+
/* Setup bars */
DL_FOREACH(bar_list, bar)
setup_bar(bar);
wl_display_roundtrip(display);
- /* Configure stdin */
- if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
- EDIE("fcntl");
+ if (!ipc) {
+ /* Configure stdin */
+ if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
+ EDIE("fcntl");
- /* Allocate stdin buffer */
- if (!(stdinbuf = malloc(1024)))
- EDIE("malloc");
- stdinbuf_cap = 1024;
+ /* Allocate stdin buffer */
+ if (!(stdinbuf = malloc(1024)))
+ EDIE("malloc");
+ stdinbuf_cap = 1024;
+ }
/* Set up socket */
for (uint32_t i = 0;; i++) {
@@ -1506,10 +1678,13 @@ main(int argc, char **argv)
close(sock_fd);
unlink(socketpath);
- free(stdinbuf);
+ if (!ipc)
+ free(stdinbuf);
zwlr_layer_shell_v1_destroy(layer_shell);
zxdg_output_manager_v1_destroy(output_manager);
+ if (ipc)
+ znet_tapesoftware_dwl_wm_v1_destroy(dwl_wm);
DL_FOREACH_SAFE(bar_list, bar, bar2)
teardown_bar(bar);
diff --git a/protocols/net-tapesoftware-dwl-wm-unstable-v1.xml b/protocols/net-tapesoftware-dwl-wm-unstable-v1.xml
new file mode 100644
index 0000000..4fe5b73
--- /dev/null
+++ b/protocols/net-tapesoftware-dwl-wm-unstable-v1.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="net_tapesoftware_dwl_wm_unstable_v1">
+ <copyright>
+ Copyright (c) 2021 Raphael Robatsch
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <interface name="znet_tapesoftware_dwl_wm_v1" version="1">
+ <description summary="control the dwl state">
+ This interface is exposed as a global in the wl_registry.
+
+ Clients can use this protocol to receive updates of the window manager
+ state (active tags, active layout, and focused window).
+ Clients can also control this state.
+
+ After binding, the client will receive the available tags and layouts
+ with the 'tag' and 'layout' events. These can be used in subsequent
+ dwl_wm_monitor_v1.set_tags/set_layout requests, and to interpret the
+ dwl_wm_monitor_v1.layout/tag events.
+ </description>
+
+ <request name="release" type="destructor">
+ <description summary="release dwl_wm">
+ This request indicates that the client will not use the dwl_wm
+ object any more. Objects that have been created through this instance
+ are not affected.
+ </description>
+ </request>
+
+ <request name="get_monitor">
+ <description summary="gets a dwl monitor from an output">
+ Gets a dwl monitor for the specified output. The window manager
+ state on the output can be controlled using the monitor.
+ </description>
+ <arg name="id" type="new_id" interface="znet_tapesoftware_dwl_wm_monitor_v1" />
+ <arg name="output" type="object" interface="wl_output" />
+ </request>
+
+ <event name="tag">
+ <description summary="announces the presence of a tag">
+ This event is sent immediately after binding.
+ A roundtrip after binding guarantees that the client has received all tags.
+ </description>
+ <arg name="name" type="string"/>
+ </event>
+
+ <event name="layout">
+ <description summary="announces the presence of a layout">
+ This event is sent immediately after binding.
+ A roundtrip after binding guarantees that the client has received all layouts.
+ </description>
+ <arg name="name" type="string"/>
+ </event>
+ </interface>
+
+ <interface name="znet_tapesoftware_dwl_wm_monitor_v1" version="1">
+ <description summary="control one monitor">
+ Observes and controls one monitor.
+
+ Events are double-buffered: Clients should cache all events and only
+ redraw themselves once the 'frame' event is sent.
+
+ Requests are not double-buffered: The compositor will update itself
+ immediately.
+ </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_monitor">
+ This request indicates that the client is done with this dwl_monitor.
+ All further requests are ignored.
+ </description>
+ </request>
+
+ <event name="selected">
+ <description summary="updates the selected state of the monitor">
+ If 'selected' is nonzero, this monitor is the currently selected one.
+ </description>
+ <arg name="selected" type="uint"/>
+ </event>
+
+ <event name="tag">
+ <description summary="updates the state of one tag">
+ Announces the update of a tag. num_clients and focused_client can be
+ used to draw client indicators.
+ </description>
+ <arg name="tag" type="uint" summary="index of a tag received by the dwl_wm_v1.tag event." />
+ <arg name="state" type="uint" enum="tag_state"/>
+ <arg name="num_clients" type="uint" summary="number of clients on this tag"/>
+ <arg name="focused_client" type="int" summary="out of num_clients. -1 if there is no focused client"/>
+ </event>
+
+ <event name="layout">
+ <description summary="updates the selected layout">
+ Announces the update of the selected layout.
+ </description>
+ <arg name="layout" type="uint" summary="index of a layout received by the dwl_wm_v1.layout event."/>
+ </event>
+
+ <event name="title">
+ <description summary="updates the focused client">
+ Announces the update of the selected client.
+ </description>
+ <arg name="title" type="string"/>
+ </event>
+
+ <event name="frame">
+ <description summary="end of status update sequence">
+ Sent after all other events belonging to the status update has been sent.
+ Clients should redraw themselves now.
+ </description>
+ </event>
+
+ <request name="set_tags">
+ <description summary="sets the active tags on this monitor.">
+ Changes are applied immediately.
+ </description>
+ <arg name="tagmask" type="uint" summary="bitmask of the tags that should be set."/>
+ <arg name="toggle_tagset" type="uint"/>
+ </request>
+
+ <request name="set_client_tags">
+ <description summary="updates the tags of the focused client.">
+ tags are updated as follows:
+ new_tags = (current_tags AND and_tags) XOR xor_tags
+
+ Changes are applied immediately.
+ </description>
+ <arg name="and_tags" type="uint"/>
+ <arg name="xor_tags" type="uint"/>
+ </request>
+
+ <request name="set_layout">
+ <description summary="sets the active layout on this monitor.">
+ Changes are applied immediately.
+ </description>
+ <arg name="layout" type="uint" summary="index of a layout received by the dwl_wm_v1.layout event."/>
+ </request>
+ </interface>
+</protocol>