Refactor, everything is basically just a callback at this point, but they appear to be more stable.
このコミットが含まれているのは:
コミット
50f998560c
|
@ -1,8 +1,6 @@
|
|||
.projectile
|
||||
dwl-bar
|
||||
bar
|
||||
run
|
||||
compile_flags.txt
|
||||
log.txt
|
||||
bar.log
|
||||
config.h
|
||||
*-protocol.*
|
||||
|
|
52
Makefile
52
Makefile
|
@ -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
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;
|
||||
}
|
||||
|
|
54
src/bar.h
54
src/bar.h
|
@ -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_
|
||||
|
|
74
src/common.h
74
src/common.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_
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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_
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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_
|
|
@ -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;
|
||||
}
|
|
@ -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
1353
src/main.c
ファイル差分が大きすぎるため省略します
差分を読み込み
|
@ -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_
|
|
@ -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);
|
||||
}
|
|
@ -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
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;
|
||||
}
|
||||
|
|
37
src/shm.h
37
src/shm.h
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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_
|
|
@ -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;
|
||||
}
|
|
@ -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_
|
読み込み中…
新しいイシューから参照