diff options
| -rw-r--r-- | src/block.c | 60 | ||||
| -rw-r--r-- | src/block.h | 71 | ||||
| -rw-r--r-- | src/blocks/scheme.h | 2 | ||||
| -rw-r--r-- | src/config.c | 94 | ||||
| -rw-r--r-- | src/config.h | 11 | ||||
| -rw-r--r-- | src/event.c | 11 | ||||
| -rw-r--r-- | src/layout.c | 138 | ||||
| -rw-r--r-- | src/layout.h | 4 |
8 files changed, 238 insertions, 153 deletions
diff --git a/src/block.c b/src/block.c index 29a8394..f735174 100644 --- a/src/block.c +++ b/src/block.c @@ -1,4 +1,5 @@ #include <string.h> +#include <assert.h> #include "block.h" #include "util.h" @@ -6,7 +7,7 @@ void block_update(block_t *block) { - if (block->update_cb != NULL) { + if (block->update_fn != NULL) { struct timespec now, diff; timespec_get(&now, TIME_UTC); diff = timespec_diff(now, block->update_last); @@ -16,47 +17,50 @@ void block_update(block_t *block) "s:label", block->label, "g:ts", ANY_LOG_FORMATTER(timespec_print), &now); - block->update_cb(block); + block->update_fn(block); block->update_last = now; } } + // NOTE: Block spec should handle its children by itself... + // if (block->type == BLOCK_GROUP) { - for (int i = 0; i < block->group.n_children; i++) - block_update(block->group.children[i]); + block_group_t *group = (block_group_t *)block; + for (size_t i = 0; i < group->n_children; i++) + block_update(group->children[i]); } } void block_copy(block_t *copy, const block_t *block) { - memcpy(copy, block, sizeof(block_t)); - - // NOTE: Strings must be copied - copy->label = strcopy(block->label); - - if (block->type == BLOCK_TEXT) { - copy->text.text = strcopy(block->text.text); - } else if (block->type == BLOCK_GROUP) { - copy->group.children = calloc(block->group.n_children, sizeof(block_t *)); - - for (int i = 0; i < block->group.n_children; i++) { - block->group.children[i] = malloc(sizeof(block_t)); - block_copy(block->group.children[i], copy->group.children[i]); - } - } +// memcpy(copy, block, sizeof(block_t)); +// +// // NOTE: Strings must be copied +// copy->label = strcopy(block->label); +// +// if (block->type == BLOCK_TEXT) { +// copy->text.text = strcopy(block->text.text); +// } else if (block->type == BLOCK_GROUP) { +// copy->group.children = calloc(block->group.n_children, sizeof(block_t *)); +// +// for (int i = 0; i < block->group.n_children; i++) { +// block->group.children[i] = malloc(sizeof(block_t)); +// block_copy(block->group.children[i], copy->group.children[i]); +// } +// } } // NOTE: This does not recursively free groups! void block_free(block_t *block) { free(block->label); - - if (block->type == BLOCK_TEXT) { - free(block->text.text); - } else if (block->type == BLOCK_GROUP) { - free(block->group.children); - } - - if (block->finalize_cb != NULL) - block->finalize_cb(block); +// +// if (block->type == BLOCK_TEXT) { +// free(block->text.text); +// } else if (block->type == BLOCK_GROUP) { +// free(block->group.children); +// } +// + assert(block->clean_fn != NULL); + block->clean_fn(block); } diff --git a/src/block.h b/src/block.h index 4254355..d9800ee 100644 --- a/src/block.h +++ b/src/block.h @@ -7,7 +7,7 @@ #include "event.h" #include "util.h" -#include "config.h" +#include "layout.h" // Element or text alignment // @@ -22,6 +22,7 @@ typedef enum { typedef enum { BLOCK_TEXT, BLOCK_GROUP, + BLOCK_SPEC, } block_type_t; typedef struct block block_t; @@ -34,45 +35,69 @@ typedef void (*block_event_t)(block_t *block, event_t event); // typedef void (*block_update_t)(block_t *block); -// Block finalization routine -// NOTE: The block state must be freed by this function +// Called to cleanup a block and free its memory // -typedef void (*block_finalize_t)(block_t *block); +typedef void (*block_clean_t)(block_t *block); -// Block struct +// Called in layout_init +// +typedef void (*block_layout_t)(block_t *block, layout_t *layout, layout_info_t info); + +// Called in layout_render +// +typedef void (*block_render_t)(layout_t *layout, cairo_t *cr); + +// Called in config_resolve_children +// +typedef struct config config_t; + +typedef bool (*block_resolve_t)(block_t *block, config_t *config); + +// The block struct // struct block { block_type_t type; char *label; bool resolved; bool hidden; - void *state; struct timespec update_interval; struct timespec update_last; - block_update_t update_cb; - block_event_t event_cb; - block_finalize_t finalize_cb; + block_update_t update_fn; + block_event_t event_fn; + block_clean_t clean_fn; + // TODO + //gradient_t bg_color; + //gradient_t line_color; color_t color; color_t line_color; unsigned int line_width; unsigned int x_padding, y_padding; unsigned int min_width, max_width; - union { - struct { - char *text; - color_t text_color; - align_t text_align; - unsigned int text_size; - } text; - struct { - unsigned int spacing; - size_t n_children; - struct block **children; - bool collapse; - } group; - }; }; +typedef struct { + block_t block; + char *text; + color_t text_color; + align_t text_align; + unsigned int text_size; +} block_text_t; + +typedef struct { + block_t block; + unsigned int spacing; + size_t n_children; + struct block **children; + bool collapse; +} block_group_t; + +typedef struct { + block_t block; + block_layout_t layout_fn; + block_render_t render_fn; + block_resolve_t resolve_fn; +} block_spec_t; + void block_update(block_t *block); void block_copy(block_t *copy, const block_t *block); diff --git a/src/blocks/scheme.h b/src/blocks/scheme.h index 1795013..b726afe 100644 --- a/src/blocks/scheme.h +++ b/src/blocks/scheme.h @@ -1,7 +1,7 @@ #ifndef COMET_SCHEME_H #define COMET_SCHEME_H -#include "../block.h" +#include "../config.h" typedef struct block_scheme block_scheme_t; diff --git a/src/config.c b/src/config.c index 84804bc..0d48ef6 100644 --- a/src/config.c +++ b/src/config.c @@ -44,9 +44,9 @@ static const config_entry_t block_entries[] = { }; static const config_entry_t block_group_entries[] = { - { "spacing", CONFIG_UINT, NULL, offsetof(block_t, group.spacing) }, - { "blocks", CONFIG_LIST, NULL, offsetof(block_t, group.children) }, - { "collapse", CONFIG_BOOL, NULL, offsetof(block_t, group.collapse) }, + { "spacing", CONFIG_UINT, NULL, offsetof(block_group_t, spacing) }, + { "blocks", CONFIG_LIST, NULL, offsetof(block_group_t, children) }, + { "collapse", CONFIG_BOOL, NULL, offsetof(block_group_t, collapse) }, { 0 }, }; @@ -58,10 +58,10 @@ static config_enum_t text_align_enum[] = { }; static const config_entry_t block_text_entries[] = { - { "text", CONFIG_STRING, NULL, offsetof(block_t, text.text) }, - { "text-color", CONFIG_COLOR, NULL, offsetof(block_t, text.text_color) }, - { "text-size", CONFIG_UINT, NULL, offsetof(block_t, text.text_size) }, - { "text-align", CONFIG_ENUM, text_align_enum, offsetof(block_t, text.text_size) }, + { "text", CONFIG_STRING, NULL, offsetof(block_text_t, text) }, + { "text-color", CONFIG_COLOR, NULL, offsetof(block_text_t, text_color) }, + { "text-size", CONFIG_UINT, NULL, offsetof(block_text_t, text_size) }, + { "text-align", CONFIG_ENUM, text_align_enum, offsetof(block_text_t, text_size) }, { 0 }, }; @@ -347,7 +347,7 @@ static config_status_t config_read_block(const block_scheme_t *scheme, block_t * return status != CONFIG_UNKNOWN || scheme == NULL || scheme->entries == NULL ? status - : config_read_entry(scheme->entries, block->state, type, section, key, value); + : config_read_entry(scheme->entries, block, type, section, key, value); } void config_init(config_t *config) @@ -364,10 +364,10 @@ void config_init(config_t *config) config->font = strcopy(config_default.font); config->n_blocks = 1; - config->blocks = calloc(1, sizeof(block_t)); - config->blocks->label = strcopy("bar"); - config->blocks->type = BLOCK_GROUP; - config->blocks->group.spacing = 10; + config->blocks = calloc(1, sizeof(block_t *)); + config->blocks[0]->label = strcopy("bar"); + config->blocks[0]->type = BLOCK_GROUP; + //config->blocks->group.spacing = 10; } void config_read(config_t *config, FILE *file) @@ -388,9 +388,9 @@ void config_read(config_t *config, FILE *file) if (section != NULL) { if (!strncmp(section, "block.", 6)) { - config->blocks = realloc(config->blocks, ++config->n_blocks * sizeof(block_t)); + config->blocks = realloc(config->blocks, ++config->n_blocks * sizeof(block_t *)); assert(config->blocks != NULL); - block = &config->blocks[config->n_blocks - 1]; + block = config->blocks[config->n_blocks - 1]; char *label = strcopy(section + 6); if (label == NULL || *label == '\0' || !strcmp(label, "bar")) { @@ -400,7 +400,7 @@ void config_read(config_t *config, FILE *file) "i:line", ini.line); } else { for (size_t i = 0; i < config->n_blocks - 1; i++) { - if (!strcmp(label, config->blocks[i].label)) { + if (!strcmp(label, config->blocks[i]->label)) { ++errors; log_value_error("Block section must have a unique label", "s:section", section, @@ -436,10 +436,10 @@ void config_read(config_t *config, FILE *file) free(block->label); block->label = label; - if (scheme->size != 0) { - block->state = malloc(scheme->size); - memset(block->state, 0, scheme->size); - } + //if (scheme->size != 0) { + // block->state = malloc(scheme->size); + // memset(block->state, 0, scheme->size); + //} goto skip_pair; } @@ -477,11 +477,11 @@ void config_read(config_t *config, FILE *file) // Try the block entries if (status == CONFIG_UNKNOWN) - block = config->blocks; + block = config->blocks[0]; } if (block != NULL) { - status = config_read_block(scheme, &config->blocks[config->n_blocks - 1], + status = config_read_block(scheme, config->blocks[config->n_blocks - 1], &type, section, key, value); } @@ -531,40 +531,48 @@ skip_pair: log_panic("Config file contained %d errors", n_errors); } -static bool config_resolve_children(config_t *config, block_t *block) +bool config_resolve_children(config_t *config, block_t *block) { block->resolved = true; + if (block->type == BLOCK_TEXT) return true; - char **children = (char **)block->group.children; - block->group.children = NULL; - block->group.n_children = 0; + if (block->type == BLOCK_SPEC) { + block_spec_t *spec = (block_spec_t *)block; + return spec->resolve_fn == NULL || spec->resolve_fn(block, config); + } + + assert(block->type == BLOCK_GROUP); + block_group_t *group = (block_group_t *)block; + + char **children = (char **)group->children; + group->children = NULL; + group->n_children = 0; if (children == NULL) return true; - size_t n = 0; - for ( ; children[n] != NULL; n++); + while (children[group->n_children] != NULL) + group->n_children++; - block->group.n_children = n; - block->group.children = malloc(n * sizeof(block_t *)); + group->children = malloc(group->n_children * sizeof(block_t *)); - for (size_t i = 0; i < n; i++) { + for (size_t i = 0; i < group->n_children; i++) { for (size_t j = 0; j < config->n_blocks; j++) { - if (&config->blocks[j] == block) + if (config->blocks[j] == block) continue; - if (!strcmp(children[i], config->blocks[j].label)) { - if (config->blocks[j].resolved) { - log_error("Block '%s' can only be referenced by one block", config->blocks[j].label); + if (!strcmp(children[i], config->blocks[j]->label)) { + if (config->blocks[j]->resolved) { + log_error("Block '%s' can only be referenced by one block", config->blocks[j]->label); return false; } - log_debug("Block '%s' is parent of '%s'", block->label, config->blocks[j].label); - block->group.children[i] = &config->blocks[j]; + log_debug("Block '%s' is parent of '%s'", block->label, config->blocks[j]->label); + group->children[i] = config->blocks[j]; - if (!config_resolve_children(config, &config->blocks[j])) + if (!config_resolve_children(config, config->blocks[j])) return false; goto next; } @@ -581,25 +589,27 @@ next: block_t *config_resolve(config_t *config) { int errors = 0; - if (config->blocks->group.children == NULL) { + block_group_t *bar = (block_group_t *)config->blocks[0]; + + if (bar->children == NULL) { errors++; log_error("Section '%s' requires at least one child", "bar"); } else { // NOTE: The first item is the main block - config->blocks->min_width = config->blocks->max_width = config->width; - errors += !config_resolve_children(config, config->blocks); + bar->block.min_width = bar->block.max_width = config->width; + errors += !config_resolve_children(config, config->blocks[0]); } if (errors > 0) log_panic("Config could not be resolved"); - return config->blocks; + return config->blocks[0]; } void config_free(config_t *config) { for (int i = 0; i < config->n_blocks; i++) - block_free(&config->blocks[i]); + block_free(config->blocks[i]); free(config->blocks); free(config->font); diff --git a/src/config.h b/src/config.h index a7d196f..48fd273 100644 --- a/src/config.h +++ b/src/config.h @@ -5,8 +5,9 @@ #include <stdint.h> #include "util.h" +#include "block.h" -typedef struct block block_t; +typedef struct config config_t; typedef enum { CONFIG_STRING, @@ -27,16 +28,16 @@ typedef struct { size_t offset; } config_entry_t; -typedef struct { +struct config { size_t n_blocks; - block_t *blocks; + block_t **blocks; char *font; char *monitor; bool override_redirect; color_t background; unsigned int width; unsigned int height; -} config_t; +}; typedef struct { const char *label; @@ -47,6 +48,8 @@ void config_init(config_t *config); void config_read(config_t *config, FILE *file); +bool config_resolve_children(config_t *config, block_t *block); + block_t *config_resolve(config_t *config); void config_free(config_t *config); diff --git a/src/event.c b/src/event.c index 0942fa1..39e408a 100644 --- a/src/event.c +++ b/src/event.c @@ -1,9 +1,10 @@ #include <assert.h> +#include "any_log.h" #include "util.h" #include "layout.h" #include "event.h" -#include "any_log.h" +#include "block.h" const char *even_type_to_string(event_type_t type) { @@ -31,7 +32,7 @@ static bool event_click(layout_t *layout, event_t event) return true; } - block_event_t event_cb = layout->block->event_cb; + block_event_t event_fn = layout->block->event_fn; log_value_debug("Block was clicked", "s:type", even_type_to_string(event.type), "i:x", event.x, @@ -41,10 +42,10 @@ static bool event_click(layout_t *layout, event_t event) "i:block_y", layout->y, "i:block_width", layout->width, "i:block_height", layout->height, - "b:callback", event_cb != NULL); + "b:callback", event_fn != NULL); - if (event_cb != NULL) { - event_cb(layout->block, event); + if (event_fn != NULL) { + event_fn(layout->block, event); log_trace("Completed event callback"); } diff --git a/src/layout.c b/src/layout.c index 92e6469..db707c5 100644 --- a/src/layout.c +++ b/src/layout.c @@ -5,6 +5,7 @@ #include "any_log.h" #include "layout.h" +#include "block.h" void layout_init(layout_t *layout, block_t *block, layout_info_t info) { @@ -19,49 +20,68 @@ void layout_init(layout_t *layout, block_t *block, layout_info_t info) layout->y_padding = block->y_padding; layout->height = info.height; - if (block->type == BLOCK_GROUP) { - int x_offset = info.x_offset; - layout->children = calloc(block->group.n_children, sizeof(layout_t)); + switch (block->type) { + case BLOCK_TEXT: { + block_text_t *text = (block_text_t *)block; + layout->pl = pango_layout_new(info.context); - for (int i = 0; i < block->group.n_children; i++) { - if (block->group.children[i]->hidden) - continue; + pango_layout_set_font_description(layout->pl, info.fontdesc); + pango_layout_set_alignment(layout->pl, text->text_align); + pango_layout_set_height(layout->pl, 0); + pango_layout_set_text(layout->pl, text->text, -1); + pango_layout_get_pixel_size(layout->pl, &layout->text_width, &layout->text_height); - layout_init(&layout->children[layout->n_children], block->group.children[i], info); - info.x_offset += layout->children[layout->n_children].width + block->group.spacing; - layout->n_children++; + size_t length = strlen(text->text); + layout->width = info.height + (length != 1) * layout->text_width; + break; } - if (block->group.collapse && layout->n_children == 1) { - layout_t *children = layout->children; - memcpy(layout, children, sizeof(layout_t)); - free(children); + case BLOCK_GROUP: { + block_group_t *group = (block_group_t *)block; + int x_offset = info.x_offset; + layout->children = calloc(group->n_children, sizeof(layout_t)); - } else if (layout->n_children > 0) { - layout_t *last = &layout->children[layout->n_children - 1]; - layout->width = last->x + last->width - x_offset; + for (size_t i = 0; i < group->n_children; i++) { + if (group->children[i]->hidden) + continue; - // NOTE: Temporary solution to make blocks not overlapping correctly - // less noticeable - if (layout->children[0].x_padding == 0) { - layout->x += 1; - layout->width -= 1; + layout_init(&layout->children[layout->n_children], group->children[i], info); + info.x_offset += layout->children[layout->n_children].width + group->spacing; + layout->n_children++; } - if (last->x_padding == 0) - layout->width -= 1; + if (group->collapse && layout->n_children == 1) { + layout_t *children = layout->children; + memcpy(layout, children, sizeof(layout_t)); + free(children); + + } else if (layout->n_children > 0) { + layout_t *last = &layout->children[layout->n_children - 1]; + layout->width = last->x + last->width - x_offset; + + // NOTE: Temporary solution to make blocks not overlapping correctly + // less noticeable + if (layout->children[0].x_padding == 0) { + layout->x += 1; + layout->width -= 1; + } + + if (last->x_padding == 0) + layout->width -= 1; + } + break; } - } else if (block->type == BLOCK_TEXT) { - layout->pl = pango_layout_new(info.context); - pango_layout_set_font_description(layout->pl, info.fontdesc); - pango_layout_set_alignment(layout->pl, block->text.text_align); - pango_layout_set_height(layout->pl, 0); - pango_layout_set_text(layout->pl, block->text.text, -1); - pango_layout_get_pixel_size(layout->pl, &layout->text_width, &layout->text_height); + case BLOCK_SPEC: { + block_spec_t *spec = (block_spec_t *)block; + // You are on your own + // TODO: Maybe check for layout correctness + spec->layout_fn(block, layout, info); + break; + } - int length = strlen(block->text.text); - layout->width = info.height + (length != 1) * layout->text_width; + default: + unreachable(); } if (layout->block->max_width > 0 && layout->width > layout->block->max_width) @@ -98,24 +118,46 @@ void layout_render(layout_t *layout, cairo_t *cr) cairo_close_path(cr); cairo_stroke(cr); - if (layout->block->type == BLOCK_GROUP) { - for (int i = 0; i < layout->n_children; i++) { - cairo_push_group(cr); - layout_render(&layout->children[i], cr); - cairo_pop_group_to_source(cr); - cairo_paint(cr); + switch (layout->block->type) { + case BLOCK_TEXT: { + block_text_t *text = (block_text_t *)layout->block; + assert(layout->n_children == 0); + + int text_x = layout->x + (layout->width - layout->text_width) / 2; + int text_y = layout->y + (layout->height - layout->text_height) / 2; + + color = text->text_color; + cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); + cairo_move_to(cr, text_x, text_y); + + pango_layout_set_text(layout->pl, text->text, -1); + pango_cairo_update_layout(cr, layout->pl); + pango_cairo_show_layout(cr, layout->pl); + break; + } + + case BLOCK_GROUP: { + for (size_t i = 0; i < layout->n_children; i++) { + cairo_push_group(cr); + layout_render(&layout->children[i], cr); + cairo_pop_group_to_source(cr); + cairo_paint(cr); + } + break; } - } else if (layout->block->type == BLOCK_TEXT) { - int text_x = layout->x + (layout->width - layout->text_width) / 2; - int text_y = layout->y + (layout->height - layout->text_height) / 2; - color = layout->block->text.text_color; - cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); - cairo_move_to(cr, text_x, text_y); + case BLOCK_SPEC: { + // NOTE: What if a special block adds children to the layout? + // For now do nothing and let them handle it, however + // this is a strange behavior in my opinion... + // + block_spec_t *spec = (block_spec_t *)layout->block; + spec->render_fn(layout, cr); + break; + } - pango_layout_set_text(layout->pl, layout->block->text.text, -1); - pango_cairo_update_layout(cr, layout->pl); - pango_cairo_show_layout(cr, layout->pl); + default: + unreachable(); } } @@ -124,7 +166,7 @@ void layout_free(layout_t *layout) if (layout->pl != NULL) g_object_unref(layout->pl); - for (int i = 0; i < layout->n_children; i++) + for (size_t i = 0; i < layout->n_children; i++) layout_free(&layout->children[i]); free(layout->children); diff --git a/src/layout.h b/src/layout.h index be63155..657ca41 100644 --- a/src/layout.h +++ b/src/layout.h @@ -5,7 +5,7 @@ #include <pango/pangocairo.h> #include <pango/pango-types.h> -#include "block.h" +typedef struct block block_t; typedef struct { PangoFontDescription *fontdesc; @@ -21,7 +21,7 @@ typedef struct layout { int width, height; int text_width, text_height; PangoLayout *pl; - int n_children; + size_t n_children; struct layout *children; } layout_t; |
