From f7fa28ab42c8058392f538b92fbf5d7ee0f1b2e8 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Mon, 6 Jul 2020 21:58:51 +0100 Subject: [PATCH] Render close, iconify and maximize buttons --- README.md | 19 ++++----- include/labwc.h | 6 +-- include/theme.h | 2 + include/theme/xbm/parse.h | 2 + include/theme/xbm/tokenize.h | 1 + src/deco.c | 80 ++++++++++++++++++++++-------------- src/output.c | 8 +++- src/theme/xbm/parse.c | 27 ++++++++++-- src/theme/xbm/tokenize.c | 2 + src/theme/xbm/xbm.c | 46 ++++++++++++++++++--- 10 files changed, 140 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 21083a90..2c2da258 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,14 @@ It is in early development and has the following aims: - Where practicable, use other software to show wall-paper, take screenshots, and so on. -[Dependencies](#dependencies) -[Roadmap](#roadmap) -[Inspiration](#inspiration) -[Design](#design) -[Configuration](#configuration) -[Integration](#integration) -[Build](#build) -[Debug](#debug) +- [Dependencies](#dependencies) +- [Roadmap](#roadmap) +- [Inspiration](#inspiration) +- [Design](#design) +- [Configuration](#configuration) +- [Integration](#integration) +- [Build](#build) +- [Debug](#debug) ## Dependencies @@ -29,9 +29,8 @@ libxml2, glib-2.0, cairo and pango. - [x] Parse [rc.xml](data/rc.xml) - [x] Parse [themerc](data/themerc) - [x] Read xbm icons -- [ ] Add maximize, minimize, close buttons +- [x] Add maximize, minimize, close buttons - [ ] Add grip -- [ ] Create `view_impl` starting with .configure - [ ] Support layer-shell background (e.g. using swaybg) - [ ] Draw better alt-tab rectangle - [ ] Try restarting and consider catching SIGHUP for --reconfigure diff --git a/include/labwc.h b/include/labwc.h index 2de3da6b..84d73d3d 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -34,8 +34,6 @@ #define XCURSOR_DEFAULT "left_ptr" #define XCURSOR_SIZE 24 #define XCURSOR_MOVE "grabbing" -#define XWL_TITLEBAR_HEIGHT (10) -#define XWL_WINDOW_BORDER (3) enum cursor_mode { LAB_CURSOR_PASSTHROUGH, @@ -93,7 +91,9 @@ struct output { enum view_type { LAB_XDG_SHELL_VIEW, LAB_XWAYLAND_VIEW }; enum deco_part { - LAB_DECO_ICON_CLOSE = 0, + LAB_DECO_BUTTON_CLOSE = 0, + LAB_DECO_BUTTON_MAXIMIZE, + LAB_DECO_BUTTON_ICONIFY, LAB_DECO_PART_TITLE, LAB_DECO_PART_TOP, LAB_DECO_PART_RIGHT, diff --git a/include/theme.h b/include/theme.h index 827c31ce..8cb2f727 100644 --- a/include/theme.h +++ b/include/theme.h @@ -15,6 +15,8 @@ struct theme { float window_active_handle_bg_color[4]; float window_inactive_title_bg_color[4]; struct wlr_texture *xbm_close; + struct wlr_texture *xbm_maximize; + struct wlr_texture *xbm_iconify; }; extern struct theme theme; diff --git a/include/theme/xbm/parse.h b/include/theme/xbm/parse.h index faaffe02..213c6567 100644 --- a/include/theme/xbm/parse.h +++ b/include/theme/xbm/parse.h @@ -22,4 +22,6 @@ struct pixmap { */ struct pixmap xbm_create_pixmap(struct token *tokens); +struct pixmap xbm_create_pixmap_builtin(const char *button); + #endif /* PARSE_H */ diff --git a/include/theme/xbm/tokenize.h b/include/theme/xbm/tokenize.h index 3a32b670..c0a64b93 100644 --- a/include/theme/xbm/tokenize.h +++ b/include/theme/xbm/tokenize.h @@ -18,6 +18,7 @@ enum token_type { #define MAX_TOKEN_SIZE (256) struct token { char name[MAX_TOKEN_SIZE]; + int value; size_t pos; enum token_type type; }; diff --git a/src/deco.c b/src/deco.c index 824f65ab..2b471d8c 100644 --- a/src/deco.c +++ b/src/deco.c @@ -5,64 +5,84 @@ */ #include "labwc.h" +#include "theme.h" + +/* Based on expected font height of Sans 8 */ +#define TITLE_HEIGHT (14) +#define BORDER_WIDTH (1) struct wlr_box deco_max_extents(struct view *view) { struct wlr_box box = { - .x = view->x - XWL_WINDOW_BORDER, - .y = view->y - XWL_TITLEBAR_HEIGHT - XWL_WINDOW_BORDER, - .width = view->surface->current.width + 2 * XWL_WINDOW_BORDER, - .height = view->surface->current.height + XWL_TITLEBAR_HEIGHT + - 2 * XWL_WINDOW_BORDER, + .x = view->x - BORDER_WIDTH, + .y = view->y - TITLE_HEIGHT - BORDER_WIDTH, + .width = view->surface->current.width + 2 * BORDER_WIDTH, + .height = view->surface->current.height + TITLE_HEIGHT + + 2 * BORDER_WIDTH, }; return box; } struct wlr_box deco_box(struct view *view, enum deco_part deco_part) { + int margin; + struct wlr_box box = { .x = 0, .y = 0, .width = 0, .height = 0 }; if (!view || !view->surface) return box; switch (deco_part) { - case LAB_DECO_ICON_CLOSE: - box.x = view->x + view->surface->current.width - 8 - 1; - box.y = view->y - XWL_TITLEBAR_HEIGHT + 1; - box.width = 8; - box.height = 8; + case LAB_DECO_BUTTON_CLOSE: + wlr_texture_get_size(theme.xbm_close, &box.width, &box.height); + margin = (TITLE_HEIGHT - box.height) / 2; + box.x = view->x + view->surface->current.width + margin - + TITLE_HEIGHT; + box.y = view->y - TITLE_HEIGHT + margin; + break; + case LAB_DECO_BUTTON_MAXIMIZE: + wlr_texture_get_size(theme.xbm_maximize, &box.width, + &box.height); + margin = (TITLE_HEIGHT - box.height) / 2; + box.x = view->x + view->surface->current.width + margin - + TITLE_HEIGHT * 2; + box.y = view->y - TITLE_HEIGHT + margin; + break; + case LAB_DECO_BUTTON_ICONIFY: + wlr_texture_get_size(theme.xbm_iconify, &box.width, + &box.height); + margin = (TITLE_HEIGHT - box.height) / 2; + box.x = view->x + view->surface->current.width + margin - + TITLE_HEIGHT * 3; + box.y = view->y - TITLE_HEIGHT + margin; break; case LAB_DECO_PART_TITLE: box.x = view->x; - box.y = view->y - XWL_TITLEBAR_HEIGHT; + box.y = view->y - TITLE_HEIGHT; box.width = view->surface->current.width; - box.height = XWL_TITLEBAR_HEIGHT; + box.height = TITLE_HEIGHT; break; case LAB_DECO_PART_TOP: - box.x = view->x - XWL_WINDOW_BORDER; - box.y = view->y - XWL_TITLEBAR_HEIGHT - XWL_WINDOW_BORDER; - box.width = - view->surface->current.width + 2 * XWL_WINDOW_BORDER; - box.height = XWL_WINDOW_BORDER; + box.x = view->x - BORDER_WIDTH; + box.y = view->y - TITLE_HEIGHT - BORDER_WIDTH; + box.width = view->surface->current.width + 2 * BORDER_WIDTH; + box.height = BORDER_WIDTH; break; case LAB_DECO_PART_RIGHT: box.x = view->x + view->surface->current.width; - box.y = view->y - XWL_TITLEBAR_HEIGHT; - box.width = XWL_WINDOW_BORDER; - box.height = - view->surface->current.height + XWL_TITLEBAR_HEIGHT; + box.y = view->y - TITLE_HEIGHT; + box.width = BORDER_WIDTH; + box.height = view->surface->current.height + TITLE_HEIGHT; break; case LAB_DECO_PART_BOTTOM: - box.x = view->x - XWL_WINDOW_BORDER; + box.x = view->x - BORDER_WIDTH; box.y = view->y + view->surface->current.height; - box.width = - view->surface->current.width + 2 * XWL_WINDOW_BORDER; - box.height = +XWL_WINDOW_BORDER; + box.width = view->surface->current.width + 2 * BORDER_WIDTH; + box.height = +BORDER_WIDTH; break; case LAB_DECO_PART_LEFT: - box.x = view->x - XWL_WINDOW_BORDER; - box.y = view->y - XWL_TITLEBAR_HEIGHT; - box.width = XWL_WINDOW_BORDER; - box.height = - view->surface->current.height + XWL_TITLEBAR_HEIGHT; + box.x = view->x - BORDER_WIDTH; + box.y = view->y - TITLE_HEIGHT; + box.width = BORDER_WIDTH; + box.height = view->surface->current.height + TITLE_HEIGHT; break; default: break; diff --git a/src/output.c b/src/output.c index a7c5cb8b..895f93ef 100644 --- a/src/output.c +++ b/src/output.c @@ -39,6 +39,8 @@ static void render_cycle_box(struct output *output) static void render_icon(struct draw_data *d, struct wlr_box box, struct wlr_texture *texture) { + if (!texture) + return; float matrix[9]; wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, d->transform_matrix); @@ -66,8 +68,12 @@ static void render_decorations(struct wlr_output *output, struct view *view) ddata.rgba = theme.window_inactive_title_bg_color; draw_rect(&ddata, deco_box(view, LAB_DECO_PART_TITLE)); - render_icon(&ddata, deco_box(view, LAB_DECO_ICON_CLOSE), + render_icon(&ddata, deco_box(view, LAB_DECO_BUTTON_CLOSE), theme.xbm_close); + render_icon(&ddata, deco_box(view, LAB_DECO_BUTTON_MAXIMIZE), + theme.xbm_maximize); + render_icon(&ddata, deco_box(view, LAB_DECO_BUTTON_ICONIFY), + theme.xbm_iconify); } struct render_data { diff --git a/src/theme/xbm/parse.c b/src/theme/xbm/parse.c index 1f4c7739..78e27b61 100644 --- a/src/theme/xbm/parse.c +++ b/src/theme/xbm/parse.c @@ -36,10 +36,12 @@ static void process_bytes(struct pixmap *pixmap, struct token *tokens) } if (!t->type) return; - int value = (int)strtol(t->name, NULL, 0); + if (t->type != TOKEN_INT) + return; int bit = 1 << (col % 8); - if (value & bit) - pixmap->data[row * pixmap->width + col] = u32(defaultcolor); + if (t->value & bit) + pixmap->data[row * pixmap->width + col] = + u32(defaultcolor); } ++t; } @@ -65,6 +67,25 @@ out: return pixmap; } +/* Assuming a 6x6 button for the time being */ +/* TODO: pass width, height, vargs bytes */ +struct pixmap xbm_create_pixmap_builtin(const char *button) +{ + struct pixmap pixmap = { 0 }; + + pixmap.width = 6; + pixmap.height = 6; + + struct token t[7]; + for (int i = 0; i < 6; i++) { + t[i].value = button[i]; + t[i].type = TOKEN_INT; + } + t[6].type = 0; + process_bytes(&pixmap, t); + return pixmap; +} + char *xbm_read_file(const char *filename) { char *line = NULL; diff --git a/src/theme/xbm/tokenize.c b/src/theme/xbm/tokenize.c index f4477fa9..8584dec5 100644 --- a/src/theme/xbm/tokenize.c +++ b/src/theme/xbm/tokenize.c @@ -96,6 +96,8 @@ struct token *xbm_tokenize(char *buffer) case '0' ... '9': add_token(TOKEN_INT); get_number_token(); + struct token *token = tokens + nr_tokens - 1; + token->value = (int)strtol(token->name, NULL, 0); continue; case '{': add_token(TOKEN_SPECIAL); diff --git a/src/theme/xbm/xbm.c b/src/theme/xbm/xbm.c index f36adf83..3df66047 100644 --- a/src/theme/xbm/xbm.c +++ b/src/theme/xbm/xbm.c @@ -10,8 +10,38 @@ #include "theme/xbm/xbm.h" #include "theme/xbm/parse.h" +/* built-in 6x6 buttons */ +char close_button_normal[] = { 0x33, 0x3f, 0x1e, 0x1e, 0x3f, 0x33 }; +char iconify_button_normal[] = { 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f }; +char max_button_normal[] = { 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f }; +char max_button_toggled[] = { 0x3e, 0x22, 0x2f, 0x29, 0x39, 0x0f }; + +/* + * TODO: parse rc.xml theme name and look for icons properly. + * Just using random icon to prove the point. + */ static char filename[] = "/usr/share/themes/Bear2/openbox-3/close.xbm"; +static struct wlr_texture *texture_from_pixmap(struct wlr_renderer *renderer, + struct pixmap *pixmap) +{ + if (!pixmap) + return NULL; + return wlr_texture_from_pixels(renderer, WL_SHM_FORMAT_ARGB8888, + pixmap->width * 4, pixmap->width, + pixmap->height, pixmap->data); +} + +static struct wlr_texture *builtin(struct wlr_renderer *renderer, + const char *button) +{ + struct pixmap pixmap = xbm_create_pixmap_builtin(button); + struct wlr_texture *texture = texture_from_pixmap(renderer, &pixmap); + if (pixmap.data) + free(pixmap.data); + return texture; +} + void xbm_load(struct wlr_renderer *renderer) { struct token *tokens; @@ -19,16 +49,20 @@ void xbm_load(struct wlr_renderer *renderer) char *buffer = xbm_read_file(filename); if (!buffer) { fprintf(stderr, "no buffer\n"); - return; + goto out; } tokens = xbm_tokenize(buffer); free(buffer); struct pixmap pixmap = xbm_create_pixmap(tokens); - free(tokens); - - theme.xbm_close = wlr_texture_from_pixels( - renderer, WL_SHM_FORMAT_ARGB8888, pixmap.width * 4, - pixmap.width, pixmap.height, pixmap.data); + theme.xbm_close = texture_from_pixmap(renderer, &pixmap); + if (tokens) + free(tokens); if (pixmap.data) free(pixmap.data); + +out: + if (!theme.xbm_close) + theme.xbm_close = builtin(renderer, close_button_normal); + theme.xbm_maximize = builtin(renderer, max_button_normal); + theme.xbm_iconify = builtin(renderer, iconify_button_normal); } -- 2.52.0