Refactor, everything is basically just a callback at this point, but they appear to be more stable.

このコミットが含まれているのは:
MadcowOG 2023-04-19 17:04:52 -07:00
コミット 50f998560c
23個のファイルの変更2202行の追加1505行の削除

4
.gitignore vendored
ファイルの表示

@ -1,8 +1,6 @@
.projectile
dwl-bar
bar
run
compile_flags.txt
log.txt
bar.log
config.h
*-protocol.*

ファイルの表示

@ -2,65 +2,71 @@
# dwl-bar
#
# @file
# @version 1.0
.POSIX:
.SUFFIXES:
VERSION = 1.0
# @version 0.0
VERSION = 0.0
PKG_CONFIG = pkg-config
#paths
# paths
PREFIX = /usr/local
MANDIR = $(PREFIX)/share/man
SRCDIR = src
# Compile flags
CC = gcc
PKGS = wayland-client wayland-cursor pangocairo
PKGS = wayland-client wayland-cursor pangocairo
FILES = $(SRCDIR)/main.c $(SRCDIR)/main.h $(SRCDIR)/log.c $(SRCDIR)/log.h \
$(SRCDIR)/render.c $(SRCDIR)/render.h $(SRCDIR)/event.c $(SRCDIR)/event.h \
$(SRCDIR)/util.c $(SRCDIR)/util.h $(SRCDIR)/shm.c $(SRCDIR)/shm.h \
$(SRCDIR)/input.c $(SRCDIR)/input.h $(SRCDIR)/user.c $(SRCDIR)/user.h \
$(SRCDIR)/bar.c $(SRCDIR)/bar.h $(SRCDIR)/config.h
OBJS = $(SRCDIR)/xdg-output-unstable-v1-protocol.o $(SRCDIR)/xdg-shell-protocol.o \
$(SRCDIR)/wlr-layer-shell-unstable-v1-protocol.o
## Compile Flags
CC = gcc
BARCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(CFLAGS)
BARLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS)
# Wayland-scanner
WAYLAND_SCANNER = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner`
WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols`
srcdir := src
all: dwl-bar
dwl-bar: $(srcdir)/xdg-shell-protocol.o $(srcdir)/xdg-output-unstable-v1-protocol.o $(srcdir)/wlr-layer-shell-unstable-v1-protocol.o $(srcdir)/main.c $(srcdir)/bar.c $(srcdir)/shm.c $(srcdir)/config.h
dwl-bar: $(FILES) $(OBJS)
$(CC) $^ $(BARLIBS) $(BARCFLAGS) -o $@
$(srcdir)/%.o: $(srcdir)/%.c $(srcdir)/%.h
$(SRCDIR)/%.o: $(SRCDIR)/%.c $(SRCDIR)/%.h
$(CC) -c $< $(BARLIBS) $(BARCFLAGS) -o $@
$(srcdir)/xdg-shell-protocol.h:
$(SRCDIR)/xdg-shell-protocol.h:
$(WAYLAND_SCANNER) client-header \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
$(srcdir)/xdg-shell-protocol.c:
$(SRCDIR)/xdg-shell-protocol.c:
$(WAYLAND_SCANNER) private-code \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
$(srcdir)/xdg-output-unstable-v1-protocol.h:
$(SRCDIR)/xdg-output-unstable-v1-protocol.h:
$(WAYLAND_SCANNER) client-header \
$(WAYLAND_PROTOCOLS)/unstable/xdg-output/xdg-output-unstable-v1.xml $@
$(srcdir)/xdg-output-unstable-v1-protocol.c:
$(SRCDIR)/xdg-output-unstable-v1-protocol.c:
$(WAYLAND_SCANNER) private-code \
$(WAYLAND_PROTOCOLS)/unstable/xdg-output/xdg-output-unstable-v1.xml $@
$(srcdir)/wlr-layer-shell-unstable-v1-protocol.h:
$(SRCDIR)/wlr-layer-shell-unstable-v1-protocol.h:
$(WAYLAND_SCANNER) client-header \
protocols/wlr-layer-shell-unstable-v1.xml $@
$(srcdir)/wlr-layer-shell-unstable-v1-protocol.c:
$(SRCDIR)/wlr-layer-shell-unstable-v1-protocol.c:
$(WAYLAND_SCANNER) private-code \
protocols/wlr-layer-shell-unstable-v1.xml $@
$(srcdir)/config.h:
$(SRCDIR)/config.h:
cp src/config.def.h $@
dev: clean $(SRCDIR)/config.h $(OBJS)
clean:
rm -f dwl-bar src/*.o src/*-protocol.*
rm -f dwl-bar src/config.h src/*.o src/*-protocol.*
dist: clean
mkdir -p dwl-bar-$(VERSION)
cp -R LICENSE Makefile README.md src patches protocols \
cp -R LICENSE Makefile README.md dwl-bar.1 src protocols \
dwl-bar-$(VERSION)
tar -caf dwl-bar-$(VERSION).tar.gz dwl-bar-$(VERSION)
rm -rf dwl-bar-$(VERSION)
@ -69,7 +75,7 @@ install: dwl-bar
mkdir -p $(PREFIX)/bin
cp -f dwl-bar $(PREFIX)/bin
chmod 755 $(PREFIX)/bin/dwl-bar
mkdir -p $(PREFIX)/man1
mkdir -p $(MANDIR)/man1
cp -f dwl-bar.1 $(MANDIR)/man1
chmod 644 $(MANDIR)/man1/dwl-bar.1

ファイルの表示

@ -13,6 +13,9 @@ prints help message and exits.
.TP
.B \-v
prints version and exits.
.TP
.B \-l
initiates logging
.SH USAGE
.SS Status
.TP

710
src/bar.c
ファイルの表示

@ -1,231 +1,232 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <wayland-client-protocol.h>
#include <pango-1.0/pango/pangocairo.h>
#include "config.h"
#include "bar.h"
#include "common.h"
#include "pango/pango-font.h"
#include "cairo.h"
#include "config.def.h"
#include "config.h"
#include "input.h"
#include "main.h"
#include "pango/pango-item.h"
#include "pango/pango-layout.h"
#include "shm.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
#include "xdg-shell-protocol.h"
#include "render.h"
#include "user.h"
#include "util.h"
#include "log.h"
#include "pango/pango.h"
#include <unistd.h>
#define ELIPSES 3
static void bar_click(struct Monitor *monitor, void *data, uint32_t button, double x, double y);
static int bar_component_add_elipses(struct BasicComponent *component, struct Pipeline *pipeline, int limit);
static struct BasicComponent *bar_component_create(struct Pipeline *pipeline);
static int bar_component_width(struct BasicComponent *component, struct Pipeline *pipeline);
static void bar_bounds(void *data, double *x, double *y, double *width, double *height);
static enum Clicked bar_get_location(struct Bar *bar, double x, double y, int *tag_index);
static void bar_layout_render(struct Pipeline *pipeline, struct Bar *bar, cairo_t *painter, int *x, int *y);
static void bar_render(struct Pipeline *pipeline, void *data, cairo_t *painter, int *x, int *y);
static void bar_tags_render(struct Pipeline *pipeline, struct Bar *bar, cairo_t *painter, int *x, int *y);
static void bar_title_render(struct Pipeline *pipeline, struct Bar *bar, cairo_t *painter, int *x, int *y);
static void bar_status_render(struct Pipeline *pipeline, struct Bar *bar, cairo_t *painter, int *x, int *y);
static int bar_width(struct Pipeline *pipeline, void *data, unsigned int future_widths);
typedef struct Font {
PangoFontDescription* description;
const struct PipelineListener bar_pipeline_listener = { .render = bar_render, .width = bar_width, };
uint height; /* This is also the same as lrpad from dwm. */
uint approx_width;
} Font;
void bar_click(struct Monitor *monitor, void *data, uint32_t button, double x, double y) {
if (!monitor || !data)
return;
typedef struct BarComponent {
PangoLayout* layout;
int x; /* Right bound of box */
} BarComponent;
struct Bar *bar = data;
const struct Binding *binding;
union Arg *argp = NULL, arg;
int tag_index = -1;
enum Clicked clicked = bar_get_location(bar, x, y, &tag_index);
typedef struct {
uint occupied;
uint focusedClient; /* If the tag has a focused client */
uint state;
BarComponent component;
} Tag;
struct Bar {
BarComponent layout, title, status;
Tag tags[9];
PangoContext* context;
/* Colors */
int background[4], foreground[4];
uint invalid; /* So we don't redraw twice. */
uint active; /* If this bar is on the active monitor */
uint floating; /* If the focused client is floating */
wl_surface* surface;
zwlr_layer_surface_v1* layer_surface;
Shm* shm;
};
static void add_elipses(PangoLayout *layout, int current_size);
static void layerSurface(void* data, zwlr_layer_surface_v1*, uint32_t serial, uint32_t width, uint32_t height);
static void frame(void* data, wl_callback* callback, uint32_t callback_data);
static void bar_render(Bar* bar);
static void bar_tags_render(Bar* bar, cairo_t* painter, int* x);
static void bar_layout_render(Bar* bar, cairo_t* painter, int* x);
static void bar_title_render(Bar* bar, cairo_t* painter, int* x);
static void bar_status_render(Bar* bar, cairo_t* painter, int* x);
static void bar_set_colorscheme(Bar* bar, const int** scheme);
static void set_color(cairo_t* painter, const int rgba[4]);
static void bar_color_background(Bar* bar, cairo_t* painter);
static void bar_color_foreground(Bar* bar, cairo_t* painter);
static Font getFont(void);
static BarComponent bar_component_create(PangoContext* context, PangoFontDescription* description);
static void bar_component_render(Bar* bar, BarComponent* component, cairo_t* painter, uint width, int* x);
static int bar_component_width(BarComponent* component);
static Font bar_font = {NULL, 0};
// So that the compositor can tell us when it's a good time to render again.
const wl_callback_listener frameListener = {.done = frame};
// So that wlroots can tell us we need to resize.
// We really only need to worry about this when the bar is visible (sometimes it isn't).
const zwlr_layer_surface_v1_listener layerSurfaceListener = {.configure = layerSurface};
void layerSurface(void* data, zwlr_layer_surface_v1* _, uint32_t serial, uint32_t width, uint32_t height) {
Bar* bar = data;
zwlr_layer_surface_v1_ack_configure(bar->layer_surface, serial);
if (bar->shm) {
if (bar->shm->width == width && bar->shm->height)
return;
shm_destroy(bar->shm);
if (clicked == Click_Tag) {
arg.ui = tag_index;
argp = &arg;
}
bar->shm = shm_create(width, height, WL_SHM_FORMAT_XRGB8888);
bar_render(bar);
}
for (int i = 0; i < LENGTH(bindings); i++) {
binding = &bindings[i];
if (clicked != binding->clicked || button != binding->button)
continue;
void frame(void* data, wl_callback* callback, uint32_t callback_data) {
Bar* bar = data;
bar_render(bar);
wl_callback_destroy(callback);
}
Font getFont(void) {
PangoFontMap* map = pango_cairo_font_map_get_default();
if (!map)
die("font map");
PangoFontDescription* desc = pango_font_description_from_string(font);
if (!desc)
die("font description");
PangoContext* context = pango_font_map_create_context(map);
if (!context)
die("temp context");
PangoFont* fnt = pango_font_map_load_font(map, context, desc);
if (!fnt)
die("font load");
PangoFontMetrics* metrics = pango_font_get_metrics(fnt, pango_language_get_default());
if (!metrics)
die("font metrics");
Font in = {
desc,
PANGO_PIXELS(pango_font_metrics_get_height(metrics)),
PANGO_PIXELS(pango_font_metrics_get_approximate_char_width(metrics))
};
pango_font_metrics_unref(metrics);
g_object_unref(fnt);
g_object_unref(context);
return in;
}
void add_elipses(PangoLayout *layout, int current_size) {
const char *str = pango_layout_get_text(layout);
char *new_str;
int i = 0;
for (i = strlen(str); (((i+ELIPSES)*bar_font.approx_width)+bar_font.height > current_size
&& i >= 0); i--);
if (i <= 0) {
pango_layout_set_text(layout, "", -1);
} else {
new_str = ecalloc(i+ELIPSES+1, sizeof(char));
new_str = strncpy(new_str, str, i*sizeof(char));
new_str[i+1] = '\0';
new_str = strcat(new_str, "...");
pango_layout_set_text(layout, new_str, -1);
free(new_str);
binding->callback(monitor, (argp && !binding->bypass) ? argp : &binding->arg);
}
}
BarComponent bar_component_create(PangoContext* context, PangoFontDescription* description) {
PangoLayout* layout = pango_layout_new(context);
pango_layout_set_font_description(layout, description);
int bar_component_add_elipses(struct BasicComponent *component, struct Pipeline *pipeline, int limit) {
const char *current_string = pango_layout_get_text(component->layout);
char *new_string;
const int elipses_amnt = 3;
int i;
return (BarComponent){ layout, 0 };
for (i = strlen(current_string);
(((i+elipses_amnt)*pipeline->font->approx_width)+pipeline->font->height > limit && i >= 0);
i--);
if (i <= 0)
return 0;
new_string = strncpy(ecalloc(i+elipses_amnt+1, sizeof(*new_string)),
current_string, i);
new_string[i+1] = '\0';
new_string = strcat(new_string, "...");
pango_layout_set_text(component->layout, new_string, -1);
free(new_string);
return bar_component_width(component, pipeline);
}
int bar_component_width(BarComponent* component) {
int w;
pango_layout_get_size(component->layout, &w, NULL);
return PANGO_PIXELS(w);
struct BasicComponent *bar_component_create(struct Pipeline *pipeline) {
if (!pipeline)
return NULL;
struct BasicComponent *component = basic_component_create(pipeline->context, pipeline->font->description);
component->tx = pipeline->font->height/2.0;
component->ty = 1;
return component;
}
void bar_set_colorscheme(Bar* bar, const int** scheme) {
for (int i = 0; i < 4; i++) {
bar->foreground[i] = scheme[0][i];
bar->background[i] = scheme[1][i];
int bar_component_width(struct BasicComponent *component, struct Pipeline *pipeline) {
return basic_component_text_width(component) + pipeline->font->height;
}
void bar_bounds(void *data, double *x, double *y, double *width, double *height) {
struct Bar *bar = data;
int bar_width = 0;
struct Tag *tag;
for (int i = 0; i < LENGTH(tags); i++) {
tag = &bar->tags[i];
bar_width += tag->component->width;
}
bar_width += bar->layout->width;
bar_width += bar->title->width;
bar_width += bar->status->width;
*x = bar->x;
*y = bar->y;
*width = bar_width;
*height = bar->pipeline->shm->height;
}
void set_color(cairo_t* painter, const int rgba[4]) {
cairo_set_source_rgba(painter, rgba[0]/255.0, rgba[1]/255.0, rgba[2]/255.0, rgba[3]/255.0);
}
enum Clicked bar_get_location(struct Bar *bar, double x, double y, int *tag_index) {
enum Clicked clicked = Click_None;
struct Tag *tag;
void bar_color_background(Bar* bar, cairo_t* painter) {
set_color(painter, bar->background);
}
void bar_color_foreground(Bar* bar, cairo_t* painter) {
set_color(painter, bar->foreground);
}
void bar_component_render(Bar* bar, BarComponent* component, cairo_t* painter, uint width, int* x) {
pango_cairo_update_layout(painter, component->layout);
component->x = *x+width;
bar_color_background(bar, painter);
cairo_rectangle(painter, *x, 0, width, bar->shm->height);
cairo_fill(painter);
bar_color_foreground(bar, painter);
cairo_move_to(painter, *x+(bar_font.height/2.0), 1);
pango_cairo_show_layout(painter, component->layout);
}
void bar_tags_render(Bar* bar, cairo_t* painter, int* x) {
for ( int i = 0; i < LENGTH(bar->tags); i++ ){
Tag* tag = &bar->tags[i];
uint tagWidth = bar_component_width(&tag->component) + bar_font.height;
/* Creating the tag */
if (tag->state & TAG_ACTIVE) {
bar_set_colorscheme(bar, schemes[Active_Scheme]);
} else if (tag->state & TAG_URGENT) {
bar_set_colorscheme(bar, schemes[Urgent_Scheme]);
} else {
bar_set_colorscheme(bar, schemes[InActive_Scheme]);
for (int i = 0; i < LENGTH(tags); i++) {
tag = &bar->tags[i];
if (basic_component_is_clicked(tag->component, x, y)) {
clicked = Click_Tag;
*tag_index = i;
return clicked;
}
}
bar_component_render(bar, &tag->component, painter, tagWidth, x);
if (basic_component_is_clicked(bar->layout, x, y))
clicked = Click_Layout;
else if (basic_component_is_clicked(bar->title, x, y))
clicked = Click_Title;
else if (basic_component_is_clicked(bar->status, x, y))
clicked = Click_Status;
return clicked;
}
struct Bar *bar_create(struct List *hotspots, struct Pipeline *pipeline) {
if (!pipeline)
return NULL;
struct Bar *bar = ecalloc(1, sizeof(*bar));
bar->pipeline = pipeline;
bar->title = bar_component_create(pipeline);
bar->layout = bar_component_create(pipeline);
bar->status = bar_component_create(pipeline);
char *status = string_create("dwl %.1f", VERSION);
pango_layout_set_text(bar->status->layout, status, strlen(status));
free(status);
for (int i = 0; i < LENGTH(tags); i++) {
struct Tag *tag = &bar->tags[i];
*tag = (struct Tag){ 0, 0, 0,
bar_component_create(pipeline) };
pango_layout_set_text(bar->tags[i].component->layout, tags[i], strlen(tags[i]));
tag->component->width = basic_component_text_width(tag->component) + pipeline->font->height;
}
pipeline_add(pipeline, &bar_pipeline_listener, bar);
struct Hotspot *hotspot = list_add(hotspots, ecalloc(1, sizeof(*hotspot)));
hotspot->click = bar_click;
hotspot->bounds = bar_bounds;
hotspot->data = bar;
bar->x = 0;
bar->y = 0;
return bar;
}
void bar_destroy(struct Bar *bar) {
if (!bar) return;
basic_component_destroy(bar->title);
basic_component_destroy(bar->layout);
basic_component_destroy(bar->status);
for (int i = 0; i < LENGTH(tags); i++) {
struct Tag *tag = &bar->tags[i];
basic_component_destroy(tag->component);
}
free(bar);
}
void bar_layout_render(struct Pipeline *pipeline, struct Bar *bar, cairo_t *painter, int *x, int *y) {
if (!bar || !pipeline)
return;
bar->layout->width = bar_component_width(bar->layout, pipeline);
bar->layout->height = pipeline->shm->height;
pipeline_set_colorscheme(pipeline, schemes[InActive_Scheme]);
basic_component_render(bar->layout, pipeline, painter, x, y);
*x += bar->layout->width;
}
void bar_render(struct Pipeline *pipeline, void *data, cairo_t *painter, int *x, int *y) {
if (!pipeline || !data)
return;
struct Bar *bar = data;
bar->x = *x;
bar->y = *y;
bar_tags_render(pipeline, bar, painter, x, y);
bar_layout_render(pipeline, bar, painter, x, y);
bar_title_render(pipeline, bar, painter, x, y);
bar_status_render(pipeline, bar, painter, x, y);
}
void bar_tags_render(struct Pipeline *pipeline, struct Bar *bar, cairo_t *painter, int *x, int *y) {
if (!bar || !pipeline)
return;
for (int i = 0; i < LENGTH(tags); i++) {
struct Tag *tag = &bar->tags[i];
if (tag->state & Tag_Active)
pipeline_set_colorscheme(pipeline, schemes[Active_Scheme]);
else if (tag->state & Tag_Urgent)
pipeline_set_colorscheme(pipeline, schemes[Urgent_Scheme]);
else
pipeline_set_colorscheme(pipeline, schemes[InActive_Scheme]);
tag->component->height = pipeline->shm->height;
basic_component_render(tag->component, pipeline, painter, x, y);
if (!tag->occupied)
goto done;
/* Creating the occupied tag box */
int boxHeight = bar_font.height / 9,
boxWidth = bar_font.height / 6 + 1;
int boxHeight = pipeline->font->height / 9,
boxWidth = pipeline->font->height / 6 + 1;
if (tag->focusedClient) {
if (tag->has_focused) {
cairo_rectangle(painter, *x + boxHeight, boxHeight, boxWidth, boxWidth);
cairo_fill(painter);
} else {
@ -234,54 +235,33 @@ void bar_tags_render(Bar* bar, cairo_t* painter, int* x) {
cairo_stroke(painter);
}
done:
*x += tagWidth;
done:
*x += tag->component->width;
}
}
void bar_layout_render(Bar* bar, cairo_t* painter, int* x) {
if (!bar)
void bar_title_render(struct Pipeline *pipeline, struct Bar *bar, cairo_t *painter, int *x, int *y) {
if (!bar || !pipeline)
return;
uint layoutWidth = bar_component_width(&bar->layout) + bar_font.height;
if (bar->active)
pipeline_set_colorscheme(pipeline, schemes[Active_Scheme]);
else
pipeline_set_colorscheme(pipeline, schemes[InActive_Scheme]);
bar_set_colorscheme(bar, schemes[InActive_Scheme]);
bar_component_render(bar, &bar->layout, painter, layoutWidth, x);
bar->title->width = pipeline->shm->width - *x - bar_component_width(bar->status, pipeline) - pipeline_get_future_widths(pipeline);
bar->title->height = pipeline->shm->height;
*x += layoutWidth;
}
if (bar_component_width(bar->title, pipeline) > bar->title->width)
bar->title->width = bar_component_width(bar->title, pipeline);
void bar_title_render(Bar* bar, cairo_t* painter, int* x) {
if (!bar)
return;
// @HUH: For some reason ww - x - (status width) works, but ww - x - status width doesn't?
int titleWidth = bar->shm->width - bar->layout.x - (bar_component_width(&bar->status) + bar_font.height);
/* If the status is larger than the title
* or
* a character can't fit in the title.
* Hopefully this helps avoid situations where the title is empty
* and renders but wouldn't if it had text.
*/
if (titleWidth < 0 || bar_font.approx_width+bar_font.height > titleWidth)
return;
/* If not all text fills the title component
* Then fit as much as possible.
*/
if ((bar_component_width(&bar->title) + bar_font.height) > titleWidth)
add_elipses(bar->title.layout, titleWidth);
bar->active ? bar_set_colorscheme(bar, schemes[Active_Scheme]) : bar_set_colorscheme(bar, schemes[InActive_Scheme]);
bar_component_render(bar, &bar->title, painter, titleWidth, x);
basic_component_render(bar->title, pipeline, painter, x, y);
if (!bar->floating)
goto done;
int boxHeight = bar_font.height / 9,
boxWidth = bar_font.height / 6 + 1;
int boxHeight = pipeline->font->height / 9,
boxWidth = pipeline->font->height / 6 + 1;
set_color(painter, grey3);
cairo_rectangle(painter, *x + boxHeight + 0.5, boxHeight + 0.5, boxWidth, boxWidth);
@ -289,224 +269,108 @@ void bar_title_render(Bar* bar, cairo_t* painter, int* x) {
cairo_stroke(painter);
done:
*x += titleWidth;
*x += bar->title->width;
}
void bar_status_render(Bar* bar, cairo_t* painter, int* x) {
if (!bar)
void bar_status_render(struct Pipeline *pipeline, struct Bar *bar, cairo_t *painter, int *x, int *y) {
if (!bar || !pipeline)
return;
uint statusWidth = bar_component_width(&bar->status) + bar_font.height;
char *previous_status = NULL;
// If the status is as large or larger than the layout then fit as much as we can.
if (statusWidth > (bar->shm->width - bar->layout.x))
add_elipses(bar->status.layout, (bar->shm->width - bar->layout.x));
bar_set_colorscheme(bar, schemes[InActive_Scheme]);
pipeline_set_colorscheme(pipeline, schemes[InActive_Scheme]);
if (!bar->active && status_on_active)
bar_set_colorscheme(bar, (const int*[4]){ grey1, grey1 } );
pipeline_set_colorscheme(pipeline, (const int *[4]){ grey1, grey1 });
bar_component_render(bar, &bar->status, painter, statusWidth, x);
}
bar->status->width = bar_component_width(bar->status, pipeline);
bar->status->height = pipeline->shm->height;
void bar_render(Bar* bar) {
if (!bar || !bar->shm)
return;
int x = 0; /* Keep track of the cairo cursor */
cairo_surface_t* image = cairo_image_surface_create_for_data(shm_data(bar->shm),
CAIRO_FORMAT_ARGB32,
bar->shm->width,
bar->shm->height,
bar->shm->stride);
cairo_t* painter = cairo_create(image);
pango_cairo_update_context(painter, bar->context);
bar_tags_render(bar, painter, &x);
bar_layout_render(bar, painter, &x);
bar_title_render(bar, painter, &x);
bar_status_render(bar, painter, &x);
wl_surface_attach(bar->surface, shm_buffer(bar->shm), 0, 0);
wl_surface_damage(bar->surface, 0, 0, bar->shm->width, bar->shm->height);
wl_surface_commit(bar->surface);
cairo_destroy(painter);
cairo_surface_destroy(image);
shm_flip(bar->shm);
bar->invalid = 0;
}
Bar* bar_create(void) {
Bar* bar = ecalloc(1, sizeof(*bar));
bar->invalid = 0;
bar->active = 0;
bar->floating = 0;
bar->context = pango_font_map_create_context(pango_cairo_font_map_get_default());
if (!bar->context)
die("pango context");
if (!bar_font.description)
bar_font = getFont();
bar->layout = bar_component_create(bar->context, bar_font.description);
bar->title = bar_component_create(bar->context, bar_font.description);
bar->status = bar_component_create(bar->context, bar_font.description);
/* Default status */
char* status = ecalloc(8, sizeof(*status));
snprintf(status, 8, "dwl %.1f", VERSION);
pango_layout_set_text(bar->status.layout, status, strlen(status));
free(status);
for (int i = 0; i < LENGTH(tags); i++) {
BarComponent component = bar_component_create(bar->context, bar_font.description);
pango_layout_set_text(component.layout, tags[i], strlen(tags[i]));
Tag tag = { 0, 0, 0, component };
bar->tags[i] = tag;
if (bar->status->width > (pipeline->shm->width - *x - pipeline_get_future_widths(pipeline))) {
previous_status = strdup(pango_layout_get_text(bar->status->layout));
bar->status->width = bar_component_add_elipses(bar->status, pipeline,
(pipeline->shm->width - *x - pipeline_get_future_widths(pipeline)));
if (bar->status->width == 0) {
free(previous_status);
return;
}
}
return bar;
}
basic_component_render(bar->status, pipeline, painter, x, y);
void bar_destroy(Bar* bar) {
uint i;
if ( !bar )
return;
if ( bar->shm )
shm_destroy(bar->shm);
if ( bar->surface )
wl_surface_destroy(bar->surface);
if ( bar->layer_surface )
zwlr_layer_surface_v1_destroy(bar->layer_surface);
if ( bar->context )
g_object_unref(bar->context);
if ( bar->layout.layout )
g_object_unref(bar->layout.layout);
if ( bar->status.layout )
g_object_unref(bar->status.layout);
if ( bar->title.layout )
g_object_unref(bar->title.layout);
for ( i = 0; i < LENGTH(tags); i++) {
Tag tag = bar->tags[i];
if (tag.component.layout)
g_object_unref(tag.component.layout);
if (previous_status) {
pango_layout_set_text(bar->status->layout, previous_status, -1);
free(previous_status);
}
return free(bar);
*x += bar->status->width;
}
// When we need to redraw the bar, because of new information or changes.
// We don't just redraw the bar immediately, we will wait for the compositor to say it's ready.
// This is only for if the bar is shown
void bar_invalidate(Bar* bar) {
if ( !bar || bar->invalid || !bar_is_visible(bar))
return;
void bar_set_active(struct Bar *bar, unsigned int is_active) {
if (!bar) return;
wl_callback* cb = wl_surface_frame(bar->surface);
wl_callback_add_listener(cb, &frameListener, bar);
wl_surface_commit(bar->surface);
bar->invalid = 1;
}
void bar_show(Bar* bar, wl_output* output) {
if (!bar || !output || bar_is_visible(bar))
return;
bar->surface = wl_compositor_create_surface(compositor);
bar->layer_surface = zwlr_layer_shell_v1_get_layer_surface(shell, bar->surface, output, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "doom.dwl-bar");
zwlr_layer_surface_v1_add_listener(bar->layer_surface, &layerSurfaceListener, bar);
int anchor = bar_top ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
zwlr_layer_surface_v1_set_anchor(bar->layer_surface,
anchor | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
int height = bar_font.height + 2;
zwlr_layer_surface_v1_set_size(bar->layer_surface, 0, height);
zwlr_layer_surface_v1_set_exclusive_zone(bar->layer_surface, height);
wl_surface_commit(bar->surface);
}
int bar_is_visible(Bar* bar) {
// This is dumb, but I don't know how else to do this.
// We do a negation to convert to boolean int.
// Then another negation to get the right boolean output.
// That is 1 when there is a surface, 0 when there isn't.
return !(!bar->surface);
}
void bar_set_layout(Bar *bar, const char* text) {
pango_layout_set_text(bar->layout.layout, text, strlen(text));
}
void bar_set_title(Bar *bar, const char* text) {
pango_layout_set_text(bar->title.layout, text, strlen(text));
}
void bar_set_status(Bar *bar, const char* text) {
pango_layout_set_text(bar->status.layout, text, strlen(text));
}
void bar_set_active(Bar* bar, uint is_active) {
bar->active = is_active;
}
void bar_set_floating(Bar* bar, uint is_floating) {
void bar_set_floating(struct Bar *bar, unsigned int is_floating) {
if (!bar) return;
bar->floating = is_floating;
}
void bar_set_tag(Bar *bar, uint i, uint state, uint occupied, uint focusedClient) {
Tag* tag = &bar->tags[i];
tag->focusedClient = focusedClient;
void bar_set_layout(struct Bar *bar, const char *text) {
if (!bar) return;
pango_layout_set_text(bar->layout->layout, text, -1);
}
void bar_set_status(struct Bar *bar, const char *text) {
if (!bar) return;
pango_layout_set_text(bar->status->layout, text, -1);
}
void bar_set_tag(struct Bar *bar, unsigned int index,
unsigned int state, unsigned int occupied, unsigned int has_focused) {
if (!bar) return;
if (!bar || index >= LENGTH(bar->tags) ) return;
struct Tag *tag = &bar->tags[index];
tag->has_focused = has_focused;
tag->occupied = occupied;
tag->state = state;
}
wl_surface* bar_get_surface(Bar *bar) {
return bar->surface;
void bar_set_title(struct Bar *bar, const char *text) {
if (!bar) return;
pango_layout_set_text(bar->title->layout, text, -1);
}
void bar_click(Bar* bar, struct Monitor* monitor, int x, int y, uint32_t button) {
Arg *argp = NULL, arg;
Clicked location = Click_None;
int bar_width(struct Pipeline *pipeline, void *data, unsigned int future_widths) {
if (!data || !pipeline) return 0;
if (x < bar->tags[LENGTH(bar->tags)-1].component.x) {
location = Click_Tag;
for (int i = 0; i < LENGTH(bar->tags); i++) {
if (x < bar->tags[i].component.x) {
arg.ui = 1<<i;
argp = &arg;
break;
}
}
} else if (x < bar->layout.x) {
location = Click_Layout;
} else if (x < bar->title.x) {
location = Click_Title;
} else {
location = Click_Status;
struct Bar *bar = data;
int width = 0, title_width, status_width;
for (int i = 0; i < LENGTH(tags); i++)
width += bar_component_width(bar->tags[i].component, pipeline);
width += bar_component_width(bar->layout, pipeline);
title_width = pipeline->shm->width - width - bar_component_width(bar->status, pipeline) - future_widths;
if (bar_component_width(bar->title, pipeline) > bar->title->width)
title_width = bar_component_width(bar->title, pipeline);
width += title_width;
status_width = bar_component_width(bar->status, pipeline);
if (status_width > (pipeline->shm->width - width - future_widths)) {
char *previous_status = strdup(pango_layout_get_text(bar->status->layout));
bar->status->width = bar_component_add_elipses(bar->status, pipeline,
(pipeline->shm->width - width - pipeline_get_future_widths(pipeline)));
pango_layout_set_text(bar->status->layout, previous_status, -1);
free(previous_status);
}
width += status_width;
if (location == Click_None)
return;
for (int i = 0; i < LENGTH(buttons); i++) {
if (buttons[i].location == location && buttons[i].button == button) {
buttons[i].func(monitor, argp ? argp : &buttons[i].arg);
return;
}
}
return width;
}

ファイルの表示

@ -1,35 +1,39 @@
#ifndef BAR_H_
#define BAR_H_
#include "wlr-layer-shell-unstable-v1-protocol.h"
#include <stdint.h>
#include <sys/types.h>
#include <wayland-client-protocol.h>
#include "common.h"
typedef struct Bar Bar;
#include "config.h"
#include "render.h"
enum TagState {
None = 0,
Active = 1,
Urgent = 2,
Tag_None = 0,
Tag_Active = 1,
Tag_Urgent = 2,
};
#define TAG_INACTIVE None
#define TAG_ACTIVE Active
#define TAG_URGENT Urgent
struct Tag {
unsigned int occupied, has_focused, state;
struct BasicComponent *component;
};
Bar* bar_create(void);
void bar_destroy(Bar* bar);
void bar_invalidate(Bar* bar);
void bar_show(Bar* bar, wl_output* output);
int bar_is_visible(Bar* bar);
void bar_click(Bar* bar, struct Monitor* monitor, int x, int y, uint32_t button);
void bar_set_status(Bar* bar, const char* text);
void bar_set_title(Bar* bar, const char* text);
void bar_set_layout(Bar* bar, const char* text);
void bar_set_active(Bar* bar, uint is_active);
void bar_set_floating(Bar* bar, uint is_floating);
void bar_set_tag(Bar* bar, uint tag, uint state, uint occupied, uint focusedClient);
wl_surface* bar_get_surface(Bar* bar);
struct Bar {
struct Pipeline *pipeline;
struct BasicComponent *layout, *title, *status;
struct Tag tags[LENGTH(tags)];
unsigned int active, floating;
unsigned int x, y;
};
struct Bar *bar_create(struct List *hotspots, struct Pipeline *pipeline);
void bar_destroy(struct Bar *bar);
void bar_set_active(struct Bar *bar, unsigned int is_active);
void bar_set_floating(struct Bar *bar, unsigned int is_floating);
void bar_set_layout(struct Bar *bar, const char *text);
void bar_set_status(struct Bar *bar, const char *text);
void bar_set_tag(struct Bar *bar, unsigned int index,
unsigned int state, unsigned int occupied, unsigned int focusedClient);
void bar_set_title(struct Bar *bar, const char *text);
extern const struct PipelineListener bar_pipeline_listener;
#endif // BAR_H_

ファイルの表示

@ -1,74 +0,0 @@
#ifndef COMMON_H_
#define COMMON_H_
#include "xdg-output-unstable-v1-protocol.h"
#include <stddef.h>
#include <sys/types.h>
#include <stdio.h>
#include <wayland-client-protocol.h>
#include <linux/input-event-codes.h>
#include <wayland-cursor.h>
#define VERSION 1.0
#define LENGTH(X) (sizeof X / sizeof X[0] )
// Commonly used typedefs which makes using these structs easier.
typedef struct wl_registry wl_registry;
typedef struct wl_interface wl_interface;
typedef struct wl_display wl_display;
typedef struct wl_compositor wl_compositor;
typedef struct wl_shm wl_shm;
typedef struct wl_shm_pool wl_shm_pool;
typedef struct wl_buffer wl_buffer;
typedef struct wl_list wl_list;
typedef struct wl_output wl_output;
typedef struct xdg_wm_base xdg_wm_base;
typedef struct zwlr_layer_shell_v1 zwlr_layer_shell_v1;
typedef struct wl_surface wl_surface;
typedef struct zwlr_layer_surface_v1 zwlr_layer_surface_v1;
typedef struct wl_callback wl_callback;
typedef struct wl_callback_listener wl_callback_listener;
typedef struct zwlr_layer_surface_v1_listener zwlr_layer_surface_v1_listener;
typedef struct zxdg_output_manager_v1 zxdg_output_manager_v1;
typedef struct zxdg_output_v1 zxdg_output_v1;
typedef struct wl_seat wl_seat;
typedef struct wl_pointer wl_pointer;
typedef struct wl_keyboard wl_keyboard;
typedef struct wl_array wl_array;
typedef struct wl_cursor_theme wl_cursor_theme;
typedef struct wl_cursor_image wl_cursor_image;
typedef struct pollfd pollfd;
typedef enum wl_shm_format wl_shm_format;
extern wl_display* display;
extern wl_compositor* compositor;
extern wl_shm* shm;
extern zwlr_layer_shell_v1* shell;
struct Monitor;
typedef enum { Click_None, Click_Tag, Click_Layout, Click_Title, Click_Status } Clicked;
typedef enum { InActive_Scheme = 0, Active_Scheme = 1, Urgent_Scheme = 2 } ColorScheme;
typedef union {
uint ui;
const void* v;
} Arg;
typedef struct {
Clicked location;
int button;
void (*func)(struct Monitor* monitor, const Arg* arg);
Arg arg;
} Button;
/* Commonly used functions for allocation and program killing */
void die(const char* fmt, ...);
void* ecalloc(size_t amnt, size_t size);
/*
* User function definitions.
* Usually used for when clicking buttons with a pointer.
*/
void spawn(struct Monitor* monitor, const Arg* arg);
#endif // COMMON_H_

ファイルの表示

@ -1,12 +1,14 @@
#ifndef CONFIG_H_
#define CONFIG_H_
#include "common.h"
#define CONFIG_H_
#include "user.h"
#include <stdlib.h>
#include <linux/input-event-codes.h>
static const int bar_top = 1; /* Boolean value, non-zero is true. If not top then bottom */
static const int status_on_active = 1; /* Display the status on active monitor only. If not then on all. */
static const char* font = "Monospace 10";
static const char* terminal[] = { "alacritty", NULL };
static const char *font = "Monospace 10";
static const char *terminal[] = { "alacritty", NULL };
/*
* Colors:
@ -24,7 +26,7 @@ static const int grey1[4] = { 34, 34, 34, 255 };
static const int grey2[4] = { 187, 187, 187, 255 };
static const int grey3[4] = { 238, 238, 238, 255 };
static const int* schemes[3][2] = {
static const int *schemes[3][2] = {
/* Scheme Type fg, bg */
[InActive_Scheme] = {grey2, grey1},
[Active_Scheme] = {grey3, cyan},
@ -34,15 +36,15 @@ static const int* schemes[3][2] = {
/*
* Tags
*/
static const char* tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
/*
* Buttons
* Structure is:
* { click location, button clicked (linux event codes), function to run, other argument input (usage varies) }
* See user.h for details on relevant structures.
*/
static const Button buttons[] = {
{ Click_Status, BTN_MIDDLE, spawn, {.v = terminal } },
static const Binding bindings[] = {
/* Click Location, button, callback, bypass, arguments */
{ Click_Status, BTN_MIDDLE, spawn, 0, {.v = terminal } },
};
#endif // CONFIG_H_

75
src/event.c ノーマルファイル
ファイルの表示

@ -0,0 +1,75 @@
#include "event.h"
#include "util.h"
#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
void events_add(struct Events *events, int fd, short mask, void *data,
void (*callback)(int, short, void *)) {
if (!events)
return;
if (events->pollfds_length == events->pollfds_capacity) {
events->pollfds = realloc(events->pollfds, sizeof(struct pollfd) * (events->pollfds_capacity+1));
events->pollfds_capacity++;
}
events->pollfds[events->pollfds_length++] = (struct pollfd){fd, mask, 0};
struct EventCallback *backcall = list_add(events->callbacks, ecalloc(1, sizeof(*backcall)));
backcall->callback = callback;
backcall->data = data;
}
struct Events *events_create(void) {
struct Events *events = ecalloc(1, sizeof(*events));
events->callbacks = list_create(0);
events->pollfds = NULL;
events->pollfds_length = 0;
events->pollfds_capacity = 0;
return events;
}
void events_destroy(struct Events *events) {
if (!events)
return;
list_elements_destroy(events->callbacks, free);
free(events->pollfds);
free(events);
}
void events_poll(struct Events *events) {
if (!events)
return;
if (poll(events->pollfds, events->pollfds_length, -1) <= 0)
return;
for (int i = 0; i < events->pollfds_length; i++) {
struct pollfd *pollfd = &events->pollfds[i];
struct EventCallback *callback = events->callbacks->data[i];
if (pollfd->revents & (pollfd->events | POLLHUP | POLLERR))
callback->callback(pollfd->fd, pollfd->revents, callback->data);
}
}
void events_remove(struct Events *events, int fd) {
if (!events)
return;
for (int i = 0; i < events->pollfds_length; i++) {
if (events->pollfds[i].fd != fd)
continue;
free(list_remove(events->callbacks, i));
events->pollfds_length--;
memmove(&events->pollfds[i], &events->pollfds[i+1],
sizeof(struct pollfd) * (events->pollfds_length - i));
}
}

22
src/event.h ノーマルファイル
ファイルの表示

@ -0,0 +1,22 @@
#ifndef EVENT_H_
#define EVENT_H_
#include "util.h"
struct EventCallback {
void (*callback)(int fd, short mask, void *data);
void *data;
};
struct Events {
struct List *callbacks; // struct EventCallback*
struct pollfd *pollfds;
int pollfds_length, pollfds_capacity;
};
void events_add(struct Events *events, int fd, short mask, void *data, void (*callback)(int fd, short mask, void *data));
struct Events *events_create(void);
void events_destroy(struct Events *events);
void events_poll(struct Events *events);
void events_remove(struct Events *events, int fd);
#endif // EVENT_H_

405
src/input.c ノーマルファイル
ファイルの表示

@ -0,0 +1,405 @@
#include "input.h"
#include "log.h"
#include "main.h"
#include "user.h"
#include "util.h"
#include "render.h"
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <linux/input-event-codes.h>
#include <wayland-client-protocol.h>
#include <wayland-cursor.h>
#include <wayland-util.h>
static int button_cmp(const void *left, const void *right);
static void pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value);
static void pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete);
static void pointer_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source);
static void pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis);
static void pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
static struct Pointer *pointer_create(struct wl_seat *seat);
static void pointer_destroy(struct Pointer *pointer);
static void pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y);
static void pointer_frame(void *data, struct wl_pointer *wl_pointer);
static void pointer_process_scroll(struct Pointer *pointer, unsigned int axis_index);
static void pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface);
static void pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y);
static void pointer_update_cursor(struct Pointer *pointer);
static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities);
static void seat_name(void *data, struct wl_seat *wl_seat, const char *name);
static void touch_cancel(void *data, struct wl_touch *wl_touch);
static struct Touch *touch_create(struct wl_seat *seat);
static void touch_destroy(struct Touch *touch);
static void touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y);
static void touch_frame(void *data, struct wl_touch *wl_touch);
static struct TouchPoint *touch_get_point(struct Touch *touch, int32_t id);
static void touch_motion(void *data, struct wl_touch *wl_touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y);
static void touch_orientation(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t orientation);
static uint32_t touch_point_to_button(struct TouchPoint *point, uint32_t time);
static void touch_shape(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t major, wl_fixed_t minor);
static void touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, int32_t id);
static uint32_t wl_axis_to_button(int axis, wl_fixed_t value);
static const struct wl_pointer_listener pointer_listener = {
.axis = pointer_axis,
.axis_discrete = pointer_axis_discrete,
.axis_source = pointer_axis_source,
.axis_stop = pointer_axis_stop,
.button = pointer_button,
.enter = pointer_enter,
.frame = pointer_frame,
.leave = pointer_leave,
.motion = pointer_motion,
};
const struct wl_seat_listener seat_listener = {
.capabilities = seat_capabilities,
.name = seat_name,
};
static const struct wl_touch_listener touch_listener = {
.cancel = touch_cancel,
.down = touch_down,
.frame = touch_frame,
.motion = touch_motion,
.orientation = touch_orientation,
.shape = touch_shape,
.up = touch_up,
};
int button_cmp(const void *left, const void *right) {
return (*(uint32_t*)left) == (*(uint32_t*)right);
}
void pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis_index, wl_fixed_t value) {
struct Pointer *pointer = data;
struct Axis *axis = &pointer->axis[axis_index];
if (axis->discrete_steps == 0
&& time - axis->update_time - SCROLL_TIMEOUT)
axis->value = 0;
axis->value += value;
axis->update_time = time;
pointer->scrolled = 1;
}
void pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) {
struct Pointer *pointer = data;
pointer->axis[axis].discrete_steps += abs(discrete);
pointer->scrolled = 1;
}
void pointer_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source) {
/* Nop */
}
void pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis) {
/* Nop */
}
void pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
struct Pointer *pointer = data;
int index;
if (state == WL_POINTER_BUTTON_STATE_PRESSED && list_cmp_find(pointer->buttons, &button, button_cmp) == -1) {
uint32_t *btn = list_add(pointer->buttons, ecalloc(1, sizeof(*btn)));
*btn = button;
}
else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
(index = list_cmp_find(pointer->buttons, &button, button_cmp)) != -1) {
free(list_remove(pointer->buttons, index));
}
}
struct Pointer *pointer_create(struct wl_seat *seat) {
if (!seat) return NULL;
struct Pointer *pointer = ecalloc(1, sizeof(*pointer));
pointer->pointer = wl_seat_get_pointer(seat);
pointer->scrolled = 0;
pointer->buttons = list_create(0);
pointer->focused_monitor = NULL;
pointer->cursor_surface = NULL;
pointer->cursor_image = NULL;
pointer->cursor_theme = NULL;
return pointer;
}
void pointer_destroy(struct Pointer *pointer) {
if (!pointer) return;
wl_pointer_release(pointer->pointer);
wl_surface_destroy(pointer->cursor_surface);
wl_cursor_theme_destroy(pointer->cursor_theme);
list_elements_destroy(pointer->buttons, free);
free(pointer);
}
void pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
struct Pointer *pointer = data;
pointer->focused_monitor = monitor_from_surface(surface);
if (!pointer->focused_monitor)
return;
pointer_update_cursor(pointer);
wl_pointer_set_cursor(wl_pointer, serial, pointer->cursor_surface,
pointer->cursor_image->hotspot_x, pointer->cursor_image->hotspot_y);
}
void pointer_frame(void *data, struct wl_pointer *wl_pointer) {
struct Pointer *pointer = data;
struct Monitor *monitor = pointer->focused_monitor;
if (!monitor) return;
for (int i = 0; i < pointer->buttons->length; i++)
process_hotspots(pointer->focused_monitor, pointer->x, pointer->y,
*(uint32_t*)pointer->buttons->data[i]);
list_elements_destroy(pointer->buttons, free);
pointer->buttons = list_create(0);
if (pointer->scrolled) {
for (int i = 0; i < 2; i++)
pointer_process_scroll(pointer, i);
}
}
void pointer_process_scroll(struct Pointer *pointer, unsigned int axis_index) {
struct Axis *axis = &pointer->axis[axis_index];
if (axis->discrete_steps) {
for (int i = 0; i < axis->discrete_steps; i++)
process_hotspots(pointer->focused_monitor, pointer->x, pointer->y, wl_axis_to_button(axis_index, axis->value));
} else {
while (abs(axis->value) > SCROLL_THRESHOLD) {
if (axis->value > 0){
process_hotspots(pointer->focused_monitor, pointer->x, pointer->y, wl_axis_to_button(axis_index, SCROLL_THRESHOLD));
axis->value -= SCROLL_THRESHOLD;
} else {
process_hotspots(pointer->focused_monitor, pointer->x, pointer->y, wl_axis_to_button(axis_index, -SCROLL_THRESHOLD));
axis->value += SCROLL_THRESHOLD;
}
}
}
}
void pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) {
struct Pointer *pointer = data;
pointer->focused_monitor = NULL;
}
void pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
struct Pointer *pointer = data;
pointer->x = wl_fixed_to_double(surface_x);
pointer->y = wl_fixed_to_double(surface_y);
}
void pointer_update_cursor(struct Pointer *pointer) {
if (!pointer)
return;
if (!pointer->cursor_surface)
pointer->cursor_surface = wl_compositor_create_surface(compositor);
if (pointer->cursor_theme)
wl_cursor_theme_destroy(pointer->cursor_theme);
unsigned int cursor_size = 24;
const char *cursor_theme = getenv("XCURSOR_THEME");
const char *env_cursor_size = getenv("XCURSOR_SIZE");
if (env_cursor_size && strlen(env_cursor_size) > 0) {
errno = 0;
char *end;
unsigned int size = strtoul(env_cursor_size, &end, 10);
if (!*end && errno == 0)
cursor_size = size;
}
pointer->cursor_theme = wl_cursor_theme_load(cursor_theme, cursor_size, shm);
pointer->cursor_image = wl_cursor_theme_get_cursor(pointer->cursor_theme, "left_ptr")->images[0];
wl_surface_attach(pointer->cursor_surface, wl_cursor_image_get_buffer(pointer->cursor_image), 0, 0);
wl_surface_commit(pointer->cursor_surface);
}
void process_hotspots(struct Monitor* monitor, double x, double y, uint32_t button) {
struct Hotspot *hotspot;
for (int i = 0; i < monitor->hotspots->length; i++) {
hotspot = monitor->hotspots->data[i];
double hotspot_x = 0, hotspot_y = 0, hotspot_width = 0, hotspot_height = 0;
hotspot->bounds(hotspot->data, &hotspot_x, &hotspot_y, &hotspot_width, &hotspot_height);
if (!( x > hotspot_x && y > hotspot_y &&
x < (hotspot_x+hotspot_width) && y < (hotspot_y+hotspot_height)))
continue;
hotspot->click(monitor, hotspot->data, button, x, y);
return;
}
}
void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) {
struct Seat *seat = data;
int has_pointer = capabilities & WL_SEAT_CAPABILITY_POINTER,
has_touch = capabilities & WL_SEAT_CAPABILITY_TOUCH;
if (!seat->pointer && has_pointer) {
seat->pointer = pointer_create(seat->seat);
wl_pointer_add_listener(seat->pointer->pointer, &pointer_listener, seat->pointer);
}
else if (seat->pointer && !has_pointer) {
pointer_destroy(seat->pointer);
}
if (!seat->touch && has_touch) {
seat->touch = touch_create(seat->seat);
wl_touch_add_listener(seat->touch->touch, &touch_listener, seat->touch);
}
else if (seat->touch && !has_touch) {
touch_destroy(seat->touch);
}
}
void seat_destroy(struct Seat *seat) {
if (!seat) return;
pointer_destroy(seat->pointer);
touch_destroy(seat->touch);
wl_seat_release(seat->seat);
free(seat);
}
void seat_name(void *data, struct wl_seat *wl_seat, const char *name) {
/* Nop */
}
void touch_cancel(void *data, struct wl_touch *wl_touch) {
struct Touch *touch = data;
struct TouchPoint *point;
for (int i = 0; i < LENGTH(touch->points); i++) {
point = &touch->points[i];
point->id = -1;
point->focused_monitor = NULL;
}
}
struct Touch *touch_create(struct wl_seat *seat) {
if (!seat) return NULL;
struct Touch *touch = ecalloc(1, sizeof(*touch));
touch->touch = wl_seat_get_touch(seat);
struct TouchPoint *point;
for (int i = 0; i < LENGTH(touch->points); i++) {
point = &touch->points[i];
point->id = -1;
point->focused_monitor = NULL;
}
return touch;
}
void touch_destroy(struct Touch *touch) {
if (!touch) return;
wl_touch_release(touch->touch);
free(touch);
}
void touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time,
struct wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y) {
struct Touch *touch = data;
struct TouchPoint *point = touch_get_point(touch, id);
if (!point)
return;
point->focused_monitor = monitor_from_surface(surface);
if (!point->focused_monitor)
return;
point->id = id;
point->time = time;
point->start_x = wl_fixed_to_double(x);
point->start_y = wl_fixed_to_double(y);
}
void touch_frame(void *data, struct wl_touch *wl_touch) {
/* Nop */
}
struct TouchPoint *touch_get_point(struct Touch *touch, int32_t id) {
struct TouchPoint *point;
int empty_index = -1;
for (int i = 0; i < LENGTH(touch->points); i++) {
point = &touch->points[i];
if (point->id == id) {
return point;
}
if (!point->focused_monitor && point->id == -1)
empty_index = i;
}
if (empty_index == -1)
return NULL;
return &touch->points[empty_index];
}
void touch_motion(void *data, struct wl_touch *wl_touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) {
struct Touch *touch = data;
struct TouchPoint *point = touch_get_point(touch, id);
if (!point)
return;
point->time = time;
point->x = wl_fixed_to_double(x);
point->y = wl_fixed_to_double(y);
}
void touch_orientation(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t orientation) {
/* Nop */
}
uint32_t touch_point_to_button(struct TouchPoint *point, uint32_t time) {
/* "progress" is a measure from 0..100 representing the fraction of the
* output the touch gesture has travelled, positive when moving to the right
* and negative when moving to the left. */
int progress = (int)((point->x - point->start_x) / point->focused_monitor->pipeline->shm->width * 100);
if (abs(progress) > 20)
return (progress > 0 ? Gesture_Right : Gesture_Left);
if (time - point->time < 500)
return BTN_LEFT;
if (time - point->time < 1000)
return BTN_RIGHT;
/* If hold time is longer than 1 second then it is a middle click. */
return BTN_MIDDLE;
}
void touch_shape(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t major, wl_fixed_t minor) {
/* Nop */
}
void touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, int32_t id) {
struct Touch *touch = data;
struct TouchPoint *point = touch_get_point(touch, id);
if (!point) return;
uint32_t button = touch_point_to_button(point, time);
process_hotspots(point->focused_monitor, point->x, point->y, button);
}
uint32_t wl_axis_to_button(int axis, wl_fixed_t value) {
int negative = wl_fixed_to_double(value) < 0;
switch (axis) {
case WL_POINTER_AXIS_VERTICAL_SCROLL:
return negative ? Scroll_Up : Scroll_Down;
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
return negative ? Scroll_Left : Scroll_Right;
default:
return 0;
}
}

65
src/input.h ノーマルファイル
ファイルの表示

@ -0,0 +1,65 @@
#ifndef INPUT_H_
#define INPUT_H_
#include "main.h"
#include "util.h"
#include "user.h"
#include <wayland-util.h>
#include <wayland-cursor.h>
#define SCROLL_TIMEOUT 1000
#define SCROLL_THRESHOLD 10000
struct TouchPoint {
int32_t id;
uint32_t time;
struct Monitor *focused_monitor;
double start_x, start_y,
x, y;
};
struct Touch {
struct wl_touch *touch;
struct TouchPoint points[16];
};
struct Axis {
wl_fixed_t value;
uint32_t discrete_steps, update_time;
};
struct Pointer {
struct wl_pointer *pointer;
struct Monitor *focused_monitor;
struct wl_cursor_theme *cursor_theme;
struct wl_cursor_image *cursor_image;
struct wl_surface *cursor_surface;
double x, y;
struct List *buttons; /* uint32_t* */
struct Axis axis[2];
int scrolled;
};
struct Seat {
uint32_t wl_name;
struct wl_seat *seat;
struct Pointer *pointer;
struct Touch *touch;
struct wl_list link;
};
struct Hotspot {
void (*click)(struct Monitor *monitor, void *data, uint32_t button, double x, double y);
void (*bounds)(void *data, double *x, double *y, double *width, double *height);
void *data;
};
extern const struct wl_seat_listener seat_listener;
void process_hotspots(struct Monitor* monitor, double x, double y, uint32_t button);
void seat_destroy(struct Seat *seat);
#endif // INPUT_H_

44
src/log.c ノーマルファイル
ファイルの表示

@ -0,0 +1,44 @@
#include "log.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
FILE *log_file = NULL;
void bar_log(enum LogLevel level, const char *fmt, ...) {
if (!log_file)
return;
va_list ap;
va_start(ap, fmt);
switch (level) {
case LOG_INFO:
fprintf(log_file, "[dwl-bar] info: ");
break;
case LOG_ERROR:
fprintf(log_file, "[dwl-bar] error: ");
break;
}
vfprintf(log_file, fmt, ap);
va_end(ap);
fputc('\n', log_file);
fflush(log_file);
}
void log_destroy(void) {
if (!log_file)
return;
fclose(log_file);
}
int setup_log(void) {
log_file = fopen("bar.log", "w");
if (!log_file)
return 0;
bar_log(LOG_INFO, "Setup Logging");
return 1;
}

10
src/log.h ノーマルファイル
ファイルの表示

@ -0,0 +1,10 @@
#ifndef LOG_H_
#define LOG_H_
enum LogLevel { LOG_INFO, LOG_ERROR };
void bar_log(enum LogLevel level, const char *fmt, ...);
void log_destroy(void);
int setup_log(void);
#endif // LOG_H_

1353
src/main.c

ファイル差分が大きすぎるため省略します 差分を読み込み

31
src/main.h ノーマルファイル
ファイルの表示

@ -0,0 +1,31 @@
#ifndef MAIN_H_
#define MAIN_H_
#include "xdg-output-unstable-v1-protocol.h"
#include <stdint.h>
#include <wayland-client.h>
#include <wayland-util.h>
#define VERSION 0.0
struct Monitor {
char *xdg_name;
uint32_t wl_name;
struct wl_output *wl_output;
struct zxdg_output_v1 *xdg_output;
struct Pipeline *pipeline;
struct List *hotspots; /* struct Hotspot* */
struct Bar *bar;
struct wl_list link;
};
void panic(const char *fmt, ...);
struct Monitor *monitor_from_surface(const struct wl_surface *surface);
extern struct wl_compositor *compositor;
extern struct zwlr_layer_shell_v1 *shell;
extern struct wl_shm *shm;
#endif // MAIN_H_

259
src/render.c ノーマルファイル
ファイルの表示

@ -0,0 +1,259 @@
#include "render.h"
#include "log.h"
#include "main.h"
#include "shm.h"
#include "util.h"
#include "config.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
#include "pango/pango-layout.h"
#include "pango/pangocairo.h"
#include <limits.h>
#include <stdlib.h>
#include <wayland-client-protocol.h>
#include <cairo.h>
static struct Font *get_font(void);
static void pipeline_frame(void* data, struct wl_callback* callback, uint32_t callback_data);
static void pipeline_layer_surface(void* data, struct zwlr_layer_surface_v1* _, uint32_t serial, uint32_t width, uint32_t height);
static void pipeline_render(struct Pipeline *pipeline);
const struct wl_callback_listener frame_listener = {.done = pipeline_frame};
const struct zwlr_layer_surface_v1_listener layer_surface_listener = {.configure = pipeline_layer_surface};
struct BasicComponent *basic_component_create(PangoContext *context, PangoFontDescription *description) {
struct BasicComponent *component = ecalloc(1, sizeof(*component));
component->layout = pango_layout_new(context);
pango_layout_set_font_description(component->layout, description);
component->x = 0;
component->y = 0;
component->width = 0;
component->height = 0;
component->tx = 0;
component->ty = 0;
return component;
}
void basic_component_destroy(struct BasicComponent *component) {
if (!component)
return;
g_object_unref(component->layout);
free(component);
}
int basic_component_is_clicked(struct BasicComponent *component, double x, double y) {
bar_log(LOG_INFO, "basic_component_is_clicked: %.1f x %.1f in %d x %d", x, y, component->x, component->x+component->width);
return (x > component->x && y > component->y &&
x < (component->x + component->width) && y < (component->y + component->height));
}
void basic_component_render(struct BasicComponent *component, struct Pipeline *pipeline,
cairo_t *painter, int *x, int *y) {
if (!component)
return;
pango_cairo_update_layout(painter, component->layout);
component->x = *x;
component->y = *y;
pipeline_color_background(pipeline, painter);
cairo_rectangle(painter, *x, *y, component->width, component->height);
cairo_fill(painter);
pipeline_color_foreground(pipeline, painter);
cairo_move_to(painter, *x+component->tx, *y+component->ty);
pango_cairo_show_layout(painter, component->layout);
}
int basic_component_text_width(struct BasicComponent *component) {
if (!component)
return 0;
int w;
pango_layout_get_size(component->layout, &w, NULL);
return PANGO_PIXELS(w);
}
struct Font *get_font(void) {
PangoFontMap* map = pango_cairo_font_map_get_default();
if (!map)
panic("font map");
PangoFontDescription* desc = pango_font_description_from_string(font);
if (!desc)
panic("font description");
PangoContext* context = pango_font_map_create_context(map);
if (!context)
panic("temp context");
PangoFont* fnt = pango_font_map_load_font(map, context, desc);
if (!fnt)
panic("font load");
PangoFontMetrics* metrics = pango_font_get_metrics(fnt, pango_language_get_default());
if (!metrics)
panic("font metrics");
struct Font *font = ecalloc(1, sizeof(*font));
font->description = desc;
font->height = PANGO_PIXELS(pango_font_metrics_get_height(metrics));
font->approx_width = PANGO_PIXELS(pango_font_metrics_get_approximate_char_width(metrics));
pango_font_metrics_unref(metrics);
g_object_unref(fnt);
g_object_unref(context);
return font;
}
void pipeline_add(struct Pipeline *pipeline, const struct PipelineListener *listener, void *data) {
if (!pipeline)
return;
struct PipelineCallback *callback = list_add(pipeline->callbacks, ecalloc(1, sizeof(*callback)));
callback->listener = listener;
callback->data = data;
}
struct Pipeline *pipeline_create(void) {
struct Pipeline *pipeline = ecalloc(1, sizeof(*pipeline));
pipeline->callbacks = list_create(0);
pipeline->current = 0;
pipeline->invalid = 0;
pipeline->context = pango_font_map_create_context(pango_cairo_font_map_get_default());
pipeline->font = get_font();
pipeline->shm = NULL;
return pipeline;
}
void pipeline_destroy(struct Pipeline *pipeline) {
if (!pipeline)
return;
list_elements_destroy(pipeline->callbacks, free);
g_object_unref(pipeline->context);
g_object_unref(pipeline->font->description);
free(pipeline->font);
shm_destroy(pipeline->shm);
wl_surface_destroy(pipeline->surface);
zwlr_layer_surface_v1_destroy(pipeline->layer_surface);
free(pipeline);
}
void pipeline_frame(void* data, struct wl_callback* callback, uint32_t callback_data) {
pipeline_render((struct Pipeline *)data);
wl_callback_destroy(callback);
}
int pipeline_get_future_widths(struct Pipeline *pipeline) {
if (!pipeline)
return 0;
int width = 0;
struct PipelineCallback *callback;
for (int i = pipeline->callbacks->length-1; i > pipeline->current; i--) {
callback = pipeline->callbacks->data[i];
width += callback->listener->width(pipeline, callback->data, width);
}
return width;
}
void pipeline_invalidate(struct Pipeline *pipeline) {
if (!pipeline || pipeline->invalid || !pipeline_is_visible(pipeline))
return;
struct wl_callback *callback = wl_surface_frame(pipeline->surface);
wl_callback_add_listener(callback, &frame_listener, pipeline);
wl_surface_commit(pipeline->surface);
pipeline->invalid = 1;
}
int pipeline_is_visible(struct Pipeline *pipeline) {
if (!pipeline) return 0;
return !(!pipeline->surface);
}
void pipeline_layer_surface(void* data, struct zwlr_layer_surface_v1* _,
uint32_t serial, uint32_t width, uint32_t height) {
struct Pipeline *pipeline = data;
zwlr_layer_surface_v1_ack_configure(pipeline->layer_surface, serial);
if (pipeline->shm) {
if (pipeline->shm->width == width && pipeline->shm->height == height)
return;
shm_destroy(pipeline->shm);
}
pipeline->shm = shm_create(width, height, WL_SHM_FORMAT_XRGB8888);
pipeline_render(pipeline);
}
void pipeline_render(struct Pipeline *pipeline) {
if (!pipeline || !pipeline->shm)
return;
int x = 0, y = 0;
cairo_surface_t *image = cairo_image_surface_create_for_data(shm_data(pipeline->shm),
CAIRO_FORMAT_ARGB32, pipeline->shm->width, pipeline->shm->height, pipeline->shm->stride);
cairo_t *painter = cairo_create(image);
pango_cairo_update_context(painter, pipeline->context);
struct PipelineCallback *callback;
for (int i = 0; i < pipeline->callbacks->length; i++) {
pipeline->current = i;
callback = pipeline->callbacks->data[i];
callback->listener->render(pipeline, callback->data, painter, &x, &y);
}
wl_surface_attach(pipeline->surface, shm_buffer(pipeline->shm), 0, 0);
wl_surface_damage(pipeline->surface, 0, 0, pipeline->shm->width, pipeline->shm->height);
wl_surface_commit(pipeline->surface);
cairo_destroy(painter);
cairo_surface_destroy(image);
shm_flip(pipeline->shm);
pipeline->invalid = 0;
}
void pipeline_show(struct Pipeline *pipeline, struct wl_output *output) {
if (!pipeline || !output || pipeline_is_visible(pipeline))
return;
pipeline->surface = wl_compositor_create_surface(compositor);
pipeline->layer_surface = zwlr_layer_shell_v1_get_layer_surface(shell, pipeline->surface, output,
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "doom.dwl-bar");
zwlr_layer_surface_v1_add_listener(pipeline->layer_surface, &layer_surface_listener, pipeline);
int anchor = bar_top ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
zwlr_layer_surface_v1_set_anchor(pipeline->layer_surface,
anchor | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
int height = pipeline->font->height + 2;
zwlr_layer_surface_v1_set_size(pipeline->layer_surface, 0, height);
zwlr_layer_surface_v1_set_exclusive_zone(pipeline->layer_surface, height);
wl_surface_commit(pipeline->surface);
}
void pipeline_set_colorscheme(struct Pipeline* pipeline, const int **scheme) {
for (int i = 0; i < 4; i++) {
pipeline->foreground[i] = scheme[0][i];
pipeline->background[i] = scheme[1][i];
}
}
void pipeline_color_foreground(struct Pipeline* pipeline, cairo_t *painter) {
set_color(painter, pipeline->foreground);
}
void pipeline_color_background(struct Pipeline* pipeline, cairo_t *painter) {
set_color(painter, pipeline->background);
}
void set_color(cairo_t *painter, const int rgba[4]) {
cairo_set_source_rgba(painter, rgba[0]/255.0, rgba[1]/255.0, rgba[2]/255.0, rgba[3]/255.0);
}

70
src/render.h ノーマルファイル
ファイルの表示

@ -0,0 +1,70 @@
#ifndef RENDER_H_
#define RENDER_H_
#include "util.h"
#include "shm.h"
#include "user.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
#include "pango/pango-types.h"
#include <pango/pango.h>
#include <cairo.h>
struct Font {
PangoFontDescription *description;
unsigned int height, approx_width;
};
/* The render pipeline, also handles click events by keeping track of each components bounds'. */
struct Pipeline {
struct List *callbacks; /* struct PipelineCallbacks* */
int current /* The current callback we are on */,
invalid;
/* Colors */
int background[4], foreground[4];
PangoContext *context;
struct Font *font;
struct Shm *shm;
struct wl_surface *surface;
struct zwlr_layer_surface_v1 *layer_surface;
};
struct PipelineListener {
void (*render)(struct Pipeline *pipeline, void *data, cairo_t *painter, int *x, int *y);
int (*width)(struct Pipeline *pipeline, void *data, unsigned int future_widths);
};
struct PipelineCallback {
const struct PipelineListener *listener;
void *data;
};
/* Basic helper component, can be used if the only thing to be displayed is text. */
struct BasicComponent {
PangoLayout *layout;
int width, height,
x, y /* box start coordinates */,
tx, ty /* text starts coordinates, tx is added to starting x coordinates. */;
};
struct BasicComponent *basic_component_create(PangoContext *context, PangoFontDescription *description);
void basic_component_destroy(struct BasicComponent *component);
int basic_component_is_clicked(struct BasicComponent *component, double x, double y);
void basic_component_render(struct BasicComponent *component, struct Pipeline *pipeline,
cairo_t *painter, int *x, int *y);
int basic_component_text_width(struct BasicComponent *component);
void pipeline_add(struct Pipeline *pipeline, const struct PipelineListener *listener, void *data);
struct Pipeline *pipeline_create(void);
void pipeline_destroy(struct Pipeline *pipeline);
int pipeline_get_future_widths(struct Pipeline *pipeline);
void pipeline_invalidate(struct Pipeline *pipeline);
int pipeline_is_visible(struct Pipeline *pipeline);
void pipeline_show(struct Pipeline *pipeline, struct wl_output *output);
void pipeline_set_colorscheme(struct Pipeline* pipeline, const int **scheme);
void pipeline_color_foreground(struct Pipeline* pipeline, cairo_t *painter);
void pipeline_color_background(struct Pipeline* pipeline, cairo_t *painter);
void set_color(cairo_t *painter, const int rgba[4]);
#endif // RENDER_H_

179
src/shm.c
ファイルの表示

@ -1,148 +1,121 @@
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "shm.h"
#include "main.h"
#include <wayland-client-protocol.h>
#include "common.h"
#include "shm.h"
/* For unmapping the mapped memory when we're finished with the shared memory. */
typedef struct MemoryMapping {
void* ptr;
int size;
} MemoryMapping;
/* To help us keep track of our wayland buffers and their data. */
typedef struct Buffer {
wl_buffer* buffer;
uint8_t* buffer_ptr;
} Buffer;
struct ShmPriv {
MemoryMapping* memory;
Buffer buffers[2];
int current; // Since we hold multiple buffers we need to know which we're currently using.
};
static MemoryMapping* memory_mapping_create(int fd, int pool_size);
void memory_mapping_destroy(MemoryMapping* map);
static Buffer buffer_create(MemoryMapping* memmap, wl_shm_pool* shm, int fd, int width, int height, int offset, wl_shm_format format);
static void buffer_destroy(Buffer* buf);
#define BUFFERS 2
static int allocate_shm(int size);
static struct Buffer buffer_create(struct MemoryMapping *memmap, struct wl_shm_pool *shm,
int fd, int width, int height, int offset, enum wl_shm_format format);
static void buffer_destroy(struct Buffer *buf);
static struct MemoryMapping memory_mapping_create(int fd, int pool_size);
static void memory_mapping_destroy(struct MemoryMapping *map);
static const int buffer_amnt = 2;
int allocate_shm(int size) {
char name[] = "wl_shm";
int fd;
if ((fd = shm_open(name, O_CREAT | O_RDWR | O_EXCL, 0600)) < 0) {
die("shm_open when allocating shm");
}
if ((fd = shm_open(name, O_CREAT | O_RDWR | O_EXCL, 0600)) < 0)
panic("shm_open when allocating shm");
shm_unlink(name);
if (ftruncate(fd, size) < 0) {
die("ftruncate when allocating shm");
}
if (ftruncate(fd, size) < 0)
panic("ftruncate when allocating shm");
return fd;
}
MemoryMapping* memory_mapping_create(int fd, int pool_size) {
MemoryMapping* map = ecalloc(1, sizeof(MemoryMapping));
void* ptr = mmap(NULL, pool_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED || !ptr) {
close(fd);
die("MAP_FAILED");
}
static struct Buffer buffer_create(struct MemoryMapping *map, struct wl_shm_pool *shm,
int fd, int width, int height, int offset, enum wl_shm_format format) {
if (!map)
panic("map is null");
map->ptr = ptr;
map->size = pool_size;
return map;
}
void memory_mapping_destroy(MemoryMapping* map) {
munmap(map->ptr, map->size);
free(map);
}
Buffer buffer_create(MemoryMapping* memmap, wl_shm_pool* pool, int fd, int width, int height, int offset, wl_shm_format format) {
int stride = width * 4,
pool_size = height * stride;
Buffer buffer;
struct Buffer buffer;
if (!memmap)
die("memmap is null");
wl_buffer* wl_buf = wl_shm_pool_create_buffer(pool, offset, width, height, stride, format);
buffer.buffer = wl_buf;
buffer.buffer_ptr = memmap->ptr+offset;
struct wl_buffer *wl_buffer = wl_shm_pool_create_buffer(shm, offset, width, height, stride, format);
buffer.buffer = wl_buffer;
buffer.buffer_ptr = map->ptr+offset;
return buffer;
}
void buffer_destroy(Buffer* buffer) {
void buffer_destroy(struct Buffer *buffer) {
if (!buffer) return;
wl_buffer_destroy(buffer->buffer);
free(buffer);
}
Shm* shm_create(int w, int h, wl_shm_format format) {
Shm* _shm = calloc(1, sizeof(Shm));
ShmPriv* priv = calloc(1, sizeof(ShmPriv));
MemoryMapping* memory;
struct MemoryMapping memory_mapping_create(int fd, int pool_size) {
struct MemoryMapping map;
void* ptr = mmap(NULL, pool_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED || !ptr) {
close(fd);
panic("MAP_FAILED");
}
map.ptr = ptr;
map.size = pool_size;
return map;
}
void memory_mapping_destroy(struct MemoryMapping *map) {
if (!map) return;
munmap(map->ptr, map->size);
free(map);
}
struct Shm *shm_create(int width, int height, enum wl_shm_format format) {
struct Shm *shared_mem = calloc(1, sizeof(*shared_mem));
int i, offset,
stride = w * 4,
size = stride * h,
total = size * buffer_amnt;
stride = width * 4,
size = stride * height,
total = size * BUFFERS;
int fd = allocate_shm(total);
memory = memory_mapping_create(fd, total);
wl_shm_pool* pool = wl_shm_create_pool(shm, fd, total);
for (i = 0; i < buffer_amnt; i++) {
struct MemoryMapping memory = memory_mapping_create(fd, total);
struct wl_shm_pool* pool = wl_shm_create_pool(shm, fd, total);
for (i = 0; i < BUFFERS; i++) {
offset = size*i;
priv->buffers[i] = buffer_create(memory, pool, fd, w, h, offset, format);
shared_mem->buffers[i] = buffer_create(&memory, pool, fd, width, height, offset, format);
}
close(fd);
wl_shm_pool_destroy(pool);
priv->memory = memory;
priv->current = 0;
shared_mem->map = memory;
shared_mem->current = 0;
_shm->priv = priv;
_shm->height = h;
_shm->width = w;
_shm->stride = stride;
shared_mem->height = height;
shared_mem->width = width;
shared_mem->stride = stride;
return _shm;
return shared_mem;
}
void shm_destroy(Shm* shm) {
uint i;
if (shm->priv->memory) {
memory_mapping_destroy(shm->priv->memory);
}
void shm_destroy(struct Shm *shm) {
if (!shm) return;
for (i = 0; i < buffer_amnt; i++) { // REVIEW this may cause problems
if (&shm->priv->buffers[i]) {
buffer_destroy(&shm->priv->buffers[i]);
}
}
memory_mapping_destroy(&shm->map);
for (int i = 0; i < BUFFERS; i++)
buffer_destroy(&shm->buffers[i]);
free(shm);
}
uint8_t* shm_data(Shm *shm) {
return shm->priv->buffers[shm->priv->current].buffer_ptr;
uint8_t *shm_data(struct Shm *shm) {
return shm->buffers[shm->current].buffer_ptr;
}
wl_buffer* shm_buffer(Shm *shm) {
return shm->priv->buffers[shm->priv->current].buffer;
struct wl_buffer *shm_buffer(struct Shm *shm) {
return shm->buffers[shm->current].buffer;
}
void shm_flip(Shm *shm) {
shm->priv->current = 1-shm->priv->current;
void shm_flip(struct Shm *shm) {
shm->current = 1-shm->current;
}

ファイルの表示

@ -1,24 +1,35 @@
#ifndef SHM_H_
#define SHM_H_
#include "common.h"
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <wayland-client-protocol.h>
typedef struct ShmPriv ShmPriv;
struct MemoryMapping {
void *ptr;
int size;
};
struct Buffer {
struct wl_buffer *buffer;
uint8_t *buffer_ptr;
};
struct Shm {
int width;
int height;
int stride;
ShmPriv* priv;
int width, height, stride, current;
struct MemoryMapping map;
struct Buffer buffers[2];
};
typedef struct Shm Shm;
Shm* shm_create(int w, int h, wl_shm_format format);
void shm_destroy(Shm* shm);
uint8_t* shm_data(Shm* shm);
wl_buffer* shm_buffer(Shm* shm);
void shm_flip(Shm* shm);
struct Shm *shm_create(int width, int height, enum wl_shm_format format);
void shm_destroy(struct Shm *shm);
uint8_t *shm_data(struct Shm *shm);
struct wl_buffer *shm_buffer(struct Shm *shm);
void shm_flip(struct Shm *shm);
#endif // SHM_H_

17
src/user.c ノーマルファイル
ファイルの表示

@ -0,0 +1,17 @@
#include "user.h"
#include "util.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void spawn(struct Monitor *monitor, const union Arg *arg) {
if (fork() != 0)
return;
char* const* argv = arg->v;
setsid();
execvp(argv[0], argv);
fprintf(stderr, "dwl-bar: execvp %s", argv[0]);
perror(" failed\n");
exit(1);
}

51
src/user.h ノーマルファイル
ファイルの表示

@ -0,0 +1,51 @@
#ifndef USER_H_
#define USER_H_
#include "main.h"
typedef struct Binding Binding;
enum Clicked {
Click_None,
Click_Tag,
Click_Layout,
Click_Title,
Click_Status,
};
enum ColorScheme {
InActive_Scheme = 0,
Active_Scheme = 1,
Urgent_Scheme = 2,
};
enum TouchGesture {
Gesture_Left,
Gesture_Right,
};
enum PointerScroll {
Scroll_Up,
Scroll_Down,
Scroll_Left,
Scroll_Right,
};
union Arg {
unsigned int ui;
int i;
const void *v;
};
struct Binding {
enum Clicked clicked;
int button;
void (*callback)(struct Monitor *monitor, const union Arg *arg);
/* Informs the click function that they should only pass the defined arg in this binding */
unsigned int bypass;
const union Arg arg;
};
void spawn(struct Monitor *monitor, const union Arg *arg);
#endif // USER_H_

141
src/util.c ノーマルファイル
ファイルの表示

@ -0,0 +1,141 @@
#include "util.h"
#include "log.h"
#include "main.h"
#include <alloca.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void list_resize(struct List *list);
void *ecalloc(size_t amnt, size_t size) {
void *p = calloc(amnt, size);
if (!p)
panic("Out of memory");
return p;
}
void *list_add(struct List *list, void *data) {
if (!list)
return NULL;
list_resize(list);
list->data[list->length++] = data;
return list->data[list->length-1];
}
void list_copy(struct List *dest, struct List *src) {
if (!dest || !src)
return;
for (int i = 0; i < src->length; i++)
list_add(dest, src->data[i]);
}
struct List *list_create(size_t initial_size) {
struct List *list = ecalloc(1, sizeof(*list));
list->allocated = initial_size > 10 ? initial_size : 10;
list->length = 0;
list->data = ecalloc(list->allocated, sizeof(void*));
return list;
}
int list_cmp_find(struct List* list, const void *data, int compare(const void *left, const void *right)) {
if (!list)
return -1;
for (int i = 0; i < list->length; i++)
if (compare(data, list->data[i]))
return i;
return -1;
}
void list_destroy(struct List *list) {
if (!list)
return;
free(list->data);
free(list);
}
void list_elements_destroy(struct List *list, void (*destroy)(void *data)) {
if (!list)
return;
for (int i = 0; i < list->length; i++)
destroy(list->data[i]);
free(list->data);
free(list);
}
int list_find(struct List* list, const void *data) {
if (!list)
return -1;
for (int i = 0; i < list->length; i++)
if (data == list->data[i])
return i;
return -1;
}
void *list_remove(struct List *list, unsigned int index) {
if (!list || index > list->length-1)
return NULL;
void *tmp = list->data[index];
list->length--;
memmove(&list->data[index], &list->data[index + 1], sizeof(void*) * (list->length - index));
return tmp;
}
void list_resize(struct List *list) {
if (list->length < list->allocated)
return;
list->allocated *= 2;
list->data = realloc(list->data, list->allocated);
}
char *string_create(const char *fmt, ...) {
va_list ap, aq;
va_start(ap, fmt);
va_copy(aq, ap);
char *str;
size_t len = vsnprintf(NULL, 0, fmt, ap) + 1;
str = ecalloc(1, len);
vsnprintf(str, len, fmt, aq);
va_end(ap);
va_end(aq);
return str;
}
char *to_delimiter(const char *string, unsigned long *start_end, char delimiter) {
if (!string || !start_end)
return NULL;
char *output;
const char *read;
unsigned long i = 0;
for (read = string + *start_end; *read != '\0' && *read != delimiter; read++)
i++;
output = strncpy(ecalloc(i+1, sizeof(*output)),
string + *start_end, i);
output[i++] = '\0';
*start_end += i;
return output;
}

29
src/util.h ノーマルファイル
ファイルの表示

@ -0,0 +1,29 @@
#ifndef UTIL_H_
#define UTIL_H_
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <wayland-util.h>
#define STRING_EQUAL(string1, string2) strcmp(string1, string2) == 0
#define STRINGN_EQUAL(string1, string2, n) strcmp(string1, string2, n) == 0
#define LENGTH(X) (sizeof X / sizeof X[0] )
struct List {
void **data;
size_t allocated, length;
};
void *ecalloc(size_t amnt, size_t size);
void *list_add(struct List *list, void *data);
void list_copy(struct List *dest, struct List *src);
struct List *list_create(size_t initial_size);
int list_cmp_find(struct List *list, const void *data, int compare(const void *left, const void *right));
void list_destroy(struct List *list);
void list_elements_destroy(struct List *list, void (*destroy)(void *data));
int list_find(struct List* list, const void *data);
void *list_remove(struct List *list, unsigned int index);
char *string_create(const char* fmt, ...);
char *to_delimiter(const char* string, ulong *start_end, char delimiter);
#endif // UTIL_H_