aboutsummaryrefslogtreecommitdiff
path: root/swaybar/render.c
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2018-03-30 00:11:00 -0400
committerGitHub <noreply@github.com>2018-03-30 00:11:00 -0400
commit9d7f47746cdcb0eed3cf41875d06a8ef238eef1c (patch)
tree997658454de40db3f8b76b68d658efaf2b686188 /swaybar/render.c
parent7162b9bea4d66d61376ad3605e23e2d83bb95201 (diff)
parentf26ecd9f58bb672fe107660ce9b37f4bf0777a8c (diff)
Merge pull request #1648 from swaywm/swaybar-layers
Port swaybar to layer shell
Diffstat (limited to 'swaybar/render.c')
-rw-r--r--swaybar/render.c517
1 files changed, 200 insertions, 317 deletions
diff --git a/swaybar/render.c b/swaybar/render.c
index 6fc09078..3d9ef66b 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -1,228 +1,120 @@
+#include <limits.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
-
-#include "client/cairo.h"
-#include "client/pango.h"
-#include "client/window.h"
+#include <wlr/util/log.h>
+#include "cairo.h"
+#include "pango.h"
+#include "pool-buffer.h"
+#include "swaybar/bar.h"
#include "swaybar/config.h"
-#include "swaybar/status_line.h"
#include "swaybar/render.h"
-#ifdef ENABLE_TRAY
-#include "swaybar/tray/tray.h"
-#include "swaybar/tray/sni.h"
-#endif
-#include "log.h"
-
-
-/* internal spacing */
-static int margin = 3;
-static int ws_horizontal_padding = 5;
-static double ws_vertical_padding = 1.5;
-static int ws_spacing = 1;
-
-/**
- * Renders a sharp line of any width and height.
- *
- * The line is drawn from (x,y) to (x+width,y+height) where width/height is 0
- * if the line has a width/height of one pixel, respectively.
- */
-static void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y, double width, double height) {
- cairo_set_source_u32(cairo, color);
-
- if (width > 1 && height > 1) {
- cairo_rectangle(cairo, x, y, width, height);
- cairo_fill(cairo);
- } else {
- if (width == 1) {
- x += 0.5;
- height += y;
- width = x;
- }
+#include "swaybar/status_line.h"
+#include "wlr-layer-shell-unstable-v1-client-protocol.h"
- if (height == 1) {
- y += 0.5;
- width += x;
- height = y;
- }
+static const int ws_horizontal_padding = 5;
+static const double ws_vertical_padding = 1.5;
+static const double border_width = 1;
- cairo_move_to(cairo, x, y);
- cairo_set_line_width(cairo, 1.0);
- cairo_line_to(cairo, width, height);
- cairo_stroke(cairo);
+static uint32_t render_status_line_text(cairo_t *cairo,
+ struct swaybar_config *config, struct status_line *status,
+ bool focused, uint32_t width, uint32_t height) {
+ if (!status->text) {
+ return 0;
}
+ cairo_set_source_u32(cairo, focused ?
+ config->colors.focused_statusline : config->colors.statusline);
+ static const int margin = 3;
+ int text_width, text_height;
+ get_text_size(cairo, config->font, &text_width, &text_height,
+ 1, config->pango_markup, "%s", status->text);
+ uint32_t ideal_height = text_height + ws_vertical_padding * 2;
+ if (height < ideal_height) {
+ return ideal_height;
+ }
+ double text_y = height / 2.0 - text_height / 2.0;
+ cairo_move_to(cairo, width - text_width - margin, (int)floor(text_y));
+ pango_printf(cairo, config->font, 1, config->pango_markup,
+ "%s", status->text);
+ return ideal_height;
}
-static void render_block(struct window *window, struct config *config, struct status_block *block, double *x, bool edge, bool is_focused) {
- int width, height, sep_width;
- get_text_size(window->cairo, window->font, &width, &height,
- window->scale, block->markup, "%s", block->full_text);
-
- int textwidth = width;
- double block_width = width;
-
- if (width < block->min_width) {
- width = block->min_width;
- }
-
- *x -= width;
-
- if (block->border != 0 && block->border_left > 0) {
- *x -= (block->border_left + margin);
- block_width += block->border_left + margin;
- }
-
- if (block->border != 0 && block->border_right > 0) {
- *x -= (block->border_right + margin);
- block_width += block->border_right + margin;
- }
-
- // Add separator
- if (!edge) {
- if (config->sep_symbol) {
- get_text_size(window->cairo, window->font, &sep_width, &height,
- window->scale, false, "%s", config->sep_symbol);
- if (sep_width > block->separator_block_width) {
- block->separator_block_width = sep_width + margin * 2;
- }
- }
-
- *x -= block->separator_block_width;
- } else {
- *x -= margin;
- }
-
- double pos = *x;
-
- block->x = (int)pos;
- block->width = (int)block_width;
-
- // render background
- if (block->background != 0x0) {
- cairo_set_source_u32(window->cairo, block->background);
- cairo_rectangle(window->cairo, pos - 0.5, 1, block_width, (window->height * window->scale) - 2);
- cairo_fill(window->cairo);
- }
-
- // render top border
- if (block->border != 0 && block->border_top > 0) {
- render_sharp_line(window->cairo, block->border,
- pos - 0.5,
- 1,
- block_width,
- block->border_top);
- }
-
- // render bottom border
- if (block->border != 0 && block->border_bottom > 0) {
- render_sharp_line(window->cairo, block->border,
- pos - 0.5,
- (window->height * window->scale) - 1 - block->border_bottom,
- block_width,
- block->border_bottom);
- }
-
- // render left border
- if (block->border != 0 && block->border_left > 0) {
- render_sharp_line(window->cairo, block->border,
- pos - 0.5,
- 1,
- block->border_left,
- (window->height * window->scale) - 2);
-
- pos += block->border_left + margin;
- }
-
- // render text
- double offset = 0;
-
- if (strncmp(block->align, "left", 5) == 0) {
- offset = pos;
- } else if (strncmp(block->align, "right", 5) == 0) {
- offset = pos + width - textwidth;
- } else if (strncmp(block->align, "center", 6) == 0) {
- offset = pos + (width - textwidth) / 2;
- }
-
- cairo_move_to(window->cairo, offset, margin);
- cairo_set_source_u32(window->cairo, block->color);
- pango_printf(window->cairo, window->font, window->scale,
- block->markup, "%s", block->full_text);
-
- pos += width;
-
- // render right border
- if (block->border != 0 && block->border_right > 0) {
- pos += margin;
-
- render_sharp_line(window->cairo, block->border,
- pos - 0.5,
- 1,
- block->border_right,
- (window->height * window->scale) - 2);
-
- pos += block->border_right;
- }
+static uint32_t render_status_line_i3bar(cairo_t *cairo,
+ struct swaybar_config *config, struct status_line *status,
+ bool focused, uint32_t width, uint32_t height) {
+ // TODO
+ return 0;
+}
- // render separator
- if (!edge && block->separator) {
- if (is_focused) {
- cairo_set_source_u32(window->cairo, config->colors.focused_separator);
- } else {
- cairo_set_source_u32(window->cairo, config->colors.separator);
- }
- if (config->sep_symbol) {
- offset = pos + (block->separator_block_width - sep_width) / 2;
- cairo_move_to(window->cairo, offset, margin);
- pango_printf(window->cairo, window->font, window->scale,
- false, "%s", config->sep_symbol);
- } else {
- cairo_set_line_width(window->cairo, 1);
- cairo_move_to(window->cairo, pos + block->separator_block_width/2,
- margin);
- cairo_line_to(window->cairo, pos + block->separator_block_width/2,
- (window->height * window->scale) - margin);
- cairo_stroke(window->cairo);
- }
+static uint32_t render_status_line(cairo_t *cairo,
+ struct swaybar_config *config, struct status_line *status,
+ bool focused, uint32_t width, uint32_t height) {
+ switch (status->protocol) {
+ case PROTOCOL_TEXT:
+ return render_status_line_text(cairo,
+ config, status, focused, width, height);
+ case PROTOCOL_I3BAR:
+ return render_status_line_i3bar(cairo,
+ config, status, focused, width, height);
+ default:
+ return 0;
}
-
}
-static const char *strip_workspace_name(bool strip_num, const char *ws_name) {
- bool strip = false;
- int i;
+static uint32_t render_binding_mode_indicator(cairo_t *cairo,
+ struct swaybar_config *config, const char *mode, double x,
+ uint32_t height) {
+ int text_width, text_height;
+ get_text_size(cairo, config->font, &text_width, &text_height,
+ 1, true, "%s", mode);
+ uint32_t ideal_height = text_height + ws_vertical_padding * 2
+ + border_width * 2;
+ if (height < ideal_height) {
+ return ideal_height;
+ }
+ uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2;
+
+ cairo_set_source_u32(cairo, config->colors.binding_mode.background);
+ cairo_rectangle(cairo, x, 0, width, height);
+ cairo_fill(cairo);
+
+ cairo_set_source_u32(cairo, config->colors.binding_mode.border);
+ cairo_rectangle(cairo, x, 0, width, border_width);
+ cairo_fill(cairo);
+ cairo_rectangle(cairo, x, 0, border_width, height);
+ cairo_fill(cairo);
+ cairo_rectangle(cairo, x + width - border_width, 0, border_width, height);
+ cairo_fill(cairo);
+ cairo_rectangle(cairo, x, height - border_width, width, border_width);
+ cairo_fill(cairo);
+
+ double text_y = height / 2.0 - text_height / 2.0;
+ cairo_set_source_u32(cairo, config->colors.binding_mode.text);
+ cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
+ pango_printf(cairo, config->font, 1, true, "%s", mode);
+ return ideal_height;
+}
- if (strip_num) {
- int len = strlen(ws_name);
- for (i = 0; i < len; ++i) {
- if (!('0' <= ws_name[i] && ws_name[i] <= '9')) {
- if (':' == ws_name[i] && i < len-1 && i > 0) {
- strip = true;
- ++i;
- }
- break;
+static const char *strip_workspace_number(const char *ws_name) {
+ size_t len = strlen(ws_name);
+ for (size_t i = 0; i < len; ++i) {
+ if (ws_name[i] < '0' || ws_name[i] > '9') {
+ if (':' == ws_name[i] && i < len - 1 && i > 0) {
+ return ws_name + i + 1;
}
+ return ws_name;
}
}
-
- if (strip) {
- return ws_name + i;
- }
-
return ws_name;
}
-void workspace_button_size(struct window *window, const char *workspace_name, int *width, int *height) {
- const char *stripped_name = strip_workspace_name(swaybar.config->strip_workspace_numbers, workspace_name);
-
- get_text_size(window->cairo, window->font, width, height,
- window->scale, true, "%s", stripped_name);
- *width += 2 * ws_horizontal_padding;
- *height += 2 * ws_vertical_padding;
-}
-
-static void render_workspace_button(struct window *window, struct config *config, struct workspace *ws, double *x) {
- const char *stripped_name = strip_workspace_name(config->strip_workspace_numbers, ws->name);
+static uint32_t render_workspace_button(cairo_t *cairo,
+ struct swaybar_config *config, struct swaybar_workspace *ws,
+ double *x, uint32_t height) {
+ const char *name = ws->name;
+ if (config->strip_workspace_numbers) {
+ name = strip_workspace_number(ws->name);
+ }
struct box_colors box_colors;
if (ws->urgent) {
@@ -235,133 +127,124 @@ static void render_workspace_button(struct window *window, struct config *config
box_colors = config->colors.inactive_workspace;
}
- int width, height;
- workspace_button_size(window, stripped_name, &width, &height);
-
- // background
- cairo_set_source_u32(window->cairo, box_colors.background);
- cairo_rectangle(window->cairo, *x, 1.5, width - 1, height);
- cairo_fill(window->cairo);
-
- // border
- cairo_set_source_u32(window->cairo, box_colors.border);
- cairo_rectangle(window->cairo, *x, 1.5, width - 1, height);
- cairo_stroke(window->cairo);
-
- // text
- cairo_set_source_u32(window->cairo, box_colors.text);
- cairo_move_to(window->cairo, (int)*x + ws_horizontal_padding, margin);
- pango_printf(window->cairo, window->font, window->scale,
- true, "%s", stripped_name);
-
- *x += width + ws_spacing;
-}
-
-static void render_binding_mode_indicator(struct window *window, struct config *config, double pos) {
- int width, height;
- get_text_size(window->cairo, window->font, &width, &height,
- window->scale, false, "%s", config->mode);
-
- // background
- cairo_set_source_u32(window->cairo, config->colors.binding_mode.background);
- cairo_rectangle(window->cairo, pos, 1.5, width + ws_horizontal_padding * 2 - 1,
- height + ws_vertical_padding * 2);
- cairo_fill(window->cairo);
-
- // border
- cairo_set_source_u32(window->cairo, config->colors.binding_mode.border);
- cairo_rectangle(window->cairo, pos, 1.5, width + ws_horizontal_padding * 2 - 1,
- height + ws_vertical_padding * 2);
- cairo_stroke(window->cairo);
-
- // text
- cairo_set_source_u32(window->cairo, config->colors.binding_mode.text);
- cairo_move_to(window->cairo, (int)pos + ws_horizontal_padding, margin);
- pango_printf(window->cairo, window->font, window->scale,
- false, "%s", config->mode);
+ int text_width, text_height;
+ get_text_size(cairo, config->font, &text_width, &text_height,
+ 1, true, "%s", name);
+ uint32_t ideal_height = ws_vertical_padding * 2 + text_height
+ + border_width * 2;
+ if (height < ideal_height) {
+ return ideal_height;
+ }
+ uint32_t width = ws_horizontal_padding * 2 + text_width + border_width * 2;
+
+ cairo_set_source_u32(cairo, box_colors.background);
+ cairo_rectangle(cairo, *x, 0, width, height);
+ cairo_fill(cairo);
+
+ cairo_set_source_u32(cairo, box_colors.border);
+ cairo_rectangle(cairo, *x, 0, width, border_width);
+ cairo_fill(cairo);
+ cairo_rectangle(cairo, *x, 0, border_width, height);
+ cairo_fill(cairo);
+ cairo_rectangle(cairo, *x + width - border_width, 0, border_width, height);
+ cairo_fill(cairo);
+ cairo_rectangle(cairo, *x, height - border_width, width, border_width);
+ cairo_fill(cairo);
+
+ double text_y = height / 2.0 - text_height / 2.0;
+ cairo_set_source_u32(cairo, box_colors.text);
+ cairo_move_to(cairo, *x + width / 2 - text_width / 2, (int)floor(text_y));
+ pango_printf(cairo, config->font, 1, true, "%s", name);
+
+ *x += width;
+ return ideal_height;
}
-void render(struct output *output, struct config *config, struct status_line *line) {
- int i;
-
- struct window *window = output->window;
- cairo_t *cairo = window->cairo;
- bool is_focused = output->focused;
-
- // Clear
- cairo_save(cairo);
- cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
- cairo_paint(cairo);
- cairo_restore(cairo);
+static uint32_t render_to_cairo(cairo_t *cairo,
+ struct swaybar *bar, struct swaybar_output *output) {
+ struct swaybar_config *config = bar->config;
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
-
- // Background
- if (is_focused) {
+ if (output->focused) {
cairo_set_source_u32(cairo, config->colors.focused_background);
} else {
cairo_set_source_u32(cairo, config->colors.background);
}
cairo_paint(cairo);
-#ifdef ENABLE_TRAY
- uint32_t tray_width = tray_render(output, config);
-#else
- const uint32_t tray_width = window->width * window->scale;
-#endif
-
- // Command output
- if (is_focused) {
- cairo_set_source_u32(cairo, config->colors.focused_statusline);
- } else {
- cairo_set_source_u32(cairo, config->colors.statusline);
- }
-
- int width, height;
-
- if (line->protocol == TEXT) {
- get_text_size(window->cairo, window->font, &width, &height,
- window->scale, config->pango_markup, "%s", line->text_line);
- cairo_move_to(cairo, tray_width - margin - width, margin);
- pango_printf(window->cairo, window->font, window->scale,
- config->pango_markup, "%s", line->text_line);
- } else if (line->protocol == I3BAR && line->block_line) {
- double pos = tray_width - 0.5;
- bool edge = true;
- for (i = line->block_line->length - 1; i >= 0; --i) {
- struct status_block *block = line->block_line->items[i];
- if (block->full_text && block->full_text[0]) {
- render_block(window, config, block, &pos, edge, is_focused);
- edge = false;
- }
- }
- }
-
- cairo_set_line_width(cairo, 1.0);
- double x = 0.5;
-
- // Workspaces
+ uint32_t max_height = 0;
+ /*
+ * Each render_* function takes the actual height of the bar, and returns
+ * the ideal height. If the actual height is too short, the render function
+ * can do whatever it wants - the buffer won't be committed. If the actual
+ * height is too tall, the render function should adapt its drawing to
+ * utilize the available space.
+ */
+ double x = 0;
if (config->workspace_buttons) {
- for (i = 0; i < output->workspaces->length; ++i) {
- struct workspace *ws = output->workspaces->items[i];
- render_workspace_button(window, config, ws, &x);
+ struct swaybar_workspace *ws;
+ wl_list_for_each_reverse(ws, &output->workspaces, link) {
+ uint32_t h = render_workspace_button(
+ cairo, config, ws, &x, output->height);
+ max_height = h > max_height ? h : max_height;
}
}
-
- // binding mode indicator
- if (config->mode && config->binding_mode_indicator) {
- render_binding_mode_indicator(window, config, x);
+ if (config->binding_mode_indicator && config->mode) {
+ uint32_t h = render_binding_mode_indicator(
+ cairo, config, config->mode, x, output->height);
+ max_height = h > max_height ? h : max_height;
+ }
+ if (bar->status) {
+ uint32_t h = render_status_line(cairo, config, bar->status,
+ output->focused, output->width, output->height);
+ max_height = h > max_height ? h : max_height;
}
+
+ return max_height > output->height ? max_height : output->height;
}
-void set_window_height(struct window *window, int height) {
- int text_width, text_height;
- get_text_size(window->cairo, window->font,
- &text_width, &text_height, window->scale, false,
- "Test string for measuring purposes");
- if (height > 0) {
- margin = (height - text_height) / 2;
- ws_vertical_padding = margin - 1.5;
- }
- window->height = (text_height + margin * 2) / window->scale;
+void render_frame(struct swaybar *bar,
+ struct swaybar_output *output) {
+ cairo_surface_t *recorder = cairo_recording_surface_create(
+ CAIRO_CONTENT_COLOR_ALPHA, NULL);
+ cairo_t *cairo = cairo_create(recorder);
+ cairo_save(cairo);
+ cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
+ cairo_paint(cairo);
+ cairo_restore(cairo);
+ uint32_t height = render_to_cairo(cairo, bar, output);
+ if (bar->config->height >= 0 && height < (uint32_t)bar->config->height) {
+ height = bar->config->height;
+ }
+ if (height != output->height) {
+ // Reconfigure surface
+ zwlr_layer_surface_v1_set_size(
+ output->layer_surface, 0, height);
+ zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height);
+ // TODO: this could infinite loop if the compositor assigns us a
+ // different height than what we asked for
+ wl_surface_commit(output->surface);
+ wl_display_roundtrip(bar->display);
+ } else {
+ // Replay recording into shm and send it off
+ output->current_buffer = get_next_buffer(bar->shm,
+ output->buffers, output->width, output->height);
+ cairo_t *shm = output->current_buffer->cairo;
+
+ cairo_save(shm);
+ cairo_set_operator(shm, CAIRO_OPERATOR_CLEAR);
+ cairo_paint(shm);
+ cairo_restore(shm);
+
+ cairo_set_source_surface(shm, recorder, 0.0, 0.0);
+ cairo_paint(shm);
+
+ wl_surface_attach(output->surface,
+ output->current_buffer->buffer, 0, 0);
+ wl_surface_damage(output->surface, 0, 0, output->width, output->height);
+ wl_surface_commit(output->surface);
+ wl_display_roundtrip(bar->display);
+ }
+ cairo_surface_destroy(recorder);
+ cairo_destroy(cairo);
}