summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-07-27 01:30:35 -0400
committerLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-08-01 22:47:54 -0400
commit72db10c2f1a1a216c50f68461a840eea3948e878 (patch)
tree8517de29e9fda0823355a44edc1b81ae2b96f69e
parentImplements swaynagbar (diff)
downloadsway-72db10c2f1a1a216c50f68461a840eea3948e878.tar.gz
sway-72db10c2f1a1a216c50f68461a840eea3948e878.tar.zst
sway-72db10c2f1a1a216c50f68461a840eea3948e878.zip
Support a detailed message in swaynagbar
-rw-r--r--include/swaynagbar/nagbar.h27
-rw-r--r--swaynagbar/main.c76
-rw-r--r--swaynagbar/nagbar.c60
-rw-r--r--swaynagbar/render.c160
-rw-r--r--swaynagbar/swaynagbar.1.scd12
5 files changed, 321 insertions, 14 deletions
diff --git a/include/swaynagbar/nagbar.h b/include/swaynagbar/nagbar.h
index 07a0d51e..8b55e4fa 100644
--- a/include/swaynagbar/nagbar.h
+++ b/include/swaynagbar/nagbar.h
@@ -7,17 +7,26 @@
7 7
8#define NAGBAR_BAR_BORDER_THICKNESS 2 8#define NAGBAR_BAR_BORDER_THICKNESS 2
9#define NAGBAR_MESSAGE_PADDING 8 9#define NAGBAR_MESSAGE_PADDING 8
10#define NAGBAR_DETAILS_BORDER_THICKNESS 3
10#define NAGBAR_BUTTON_BORDER_THICKNESS 3 11#define NAGBAR_BUTTON_BORDER_THICKNESS 3
11#define NAGBAR_BUTTON_GAP 20 12#define NAGBAR_BUTTON_GAP 20
12#define NAGBAR_BUTTON_GAP_CLOSE 15 13#define NAGBAR_BUTTON_GAP_CLOSE 15
13#define NAGBAR_BUTTON_MARGIN_RIGHT 2 14#define NAGBAR_BUTTON_MARGIN_RIGHT 2
14#define NAGBAR_BUTTON_PADDING 3 15#define NAGBAR_BUTTON_PADDING 3
15 16
17#define NAGBAR_MAX_HEIGHT 500
18
16enum sway_nagbar_type { 19enum sway_nagbar_type {
17 NAGBAR_ERROR, 20 NAGBAR_ERROR,
18 NAGBAR_WARNING, 21 NAGBAR_WARNING,
19}; 22};
20 23
24enum sway_nagbar_action_type {
25 NAGBAR_ACTION_DISMISS,
26 NAGBAR_ACTION_EXPAND,
27 NAGBAR_ACTION_COMMAND,
28};
29
21struct sway_nagbar_colors { 30struct sway_nagbar_colors {
22 uint32_t button_background; 31 uint32_t button_background;
23 uint32_t background; 32 uint32_t background;
@@ -43,6 +52,7 @@ struct sway_nagbar_output {
43 52
44struct sway_nagbar_button { 53struct sway_nagbar_button {
45 char *text; 54 char *text;
55 enum sway_nagbar_action_type type;
46 char *action; 56 char *action;
47 int x; 57 int x;
48 int y; 58 int y;
@@ -50,6 +60,22 @@ struct sway_nagbar_button {
50 int height; 60 int height;
51}; 61};
52 62
63struct sway_nagbar_details {
64 bool visible;
65 char *message;
66
67 int x;
68 int y;
69 int width;
70 int height;
71
72 int offset;
73 int visible_lines;
74 int total_lines;
75 struct sway_nagbar_button button_up;
76 struct sway_nagbar_button button_down;
77};
78
53struct sway_nagbar { 79struct sway_nagbar {
54 bool run_display; 80 bool run_display;
55 int querying_outputs; 81 int querying_outputs;
@@ -77,6 +103,7 @@ struct sway_nagbar {
77 char *message; 103 char *message;
78 char *font; 104 char *font;
79 list_t *buttons; 105 list_t *buttons;
106 struct sway_nagbar_details details;
80}; 107};
81 108
82void nagbar_setup(struct sway_nagbar *nagbar); 109void nagbar_setup(struct sway_nagbar *nagbar);
diff --git a/swaynagbar/main.c b/swaynagbar/main.c
index f5ed064e..389118c6 100644
--- a/swaynagbar/main.c
+++ b/swaynagbar/main.c
@@ -3,6 +3,7 @@
3#include <signal.h> 3#include <signal.h>
4#include "log.h" 4#include "log.h"
5#include "list.h" 5#include "list.h"
6#include "readline.h"
6#include "swaynagbar/nagbar.h" 7#include "swaynagbar/nagbar.h"
7#include "wlr-layer-shell-unstable-v1-client-protocol.h" 8#include "wlr-layer-shell-unstable-v1-client-protocol.h"
8 9
@@ -34,6 +35,32 @@ static void set_nagbar_colors() {
34 } 35 }
35} 36}
36 37
38static char *read_from_stdin() {
39 char *buffer = NULL;
40 while (!feof(stdin)) {
41 char *line = read_line(stdin);
42 if (!line) {
43 continue;
44 }
45
46 if (!buffer) {
47 buffer = strdup(line);
48 } else {
49 buffer = realloc(buffer, strlen(buffer) + strlen(line) + 2);
50 strcat(buffer, line);
51 strcat(buffer, "\n");
52 }
53
54 free(line);
55 }
56
57 if (buffer && buffer[strlen(buffer) - 1] == '\n') {
58 buffer[strlen(buffer) - 1] = '\0';
59 }
60
61 return buffer;
62}
63
37int main(int argc, char **argv) { 64int main(int argc, char **argv) {
38 int exit_code = EXIT_SUCCESS; 65 int exit_code = EXIT_SUCCESS;
39 bool debug = false; 66 bool debug = false;
@@ -50,17 +77,25 @@ int main(int argc, char **argv) {
50 struct sway_nagbar_button *button_close = 77 struct sway_nagbar_button *button_close =
51 calloc(sizeof(struct sway_nagbar_button), 1); 78 calloc(sizeof(struct sway_nagbar_button), 1);
52 button_close->text = strdup("X"); 79 button_close->text = strdup("X");
53 button_close->action = NULL; 80 button_close->type = NAGBAR_ACTION_DISMISS;
54 list_add(nagbar.buttons, button_close); 81 list_add(nagbar.buttons, button_close);
55 82
56 static struct option long_options[] = { 83 struct sway_nagbar_button *button_details =
84 calloc(sizeof(struct sway_nagbar_button), 1);
85 button_details->text = strdup("Toggle Details");
86 button_details->type = NAGBAR_ACTION_EXPAND;
87
88 static struct option opts[] = {
57 {"button", required_argument, NULL, 'b'}, 89 {"button", required_argument, NULL, 'b'},
58 {"debug", no_argument, NULL, 'd'}, 90 {"debug", no_argument, NULL, 'd'},
59 {"edge", required_argument, NULL, 'e'}, 91 {"edge", required_argument, NULL, 'e'},
60 {"font", required_argument, NULL, 'f'}, 92 {"font", required_argument, NULL, 'f'},
61 {"help", no_argument, NULL, 'h'}, 93 {"help", no_argument, NULL, 'h'},
94 {"detailed-message", required_argument, NULL, 'l'},
95 {"detailed-button", required_argument, NULL, 'L'},
62 {"message", required_argument, NULL, 'm'}, 96 {"message", required_argument, NULL, 'm'},
63 {"output", required_argument, NULL, 'o'}, 97 {"output", required_argument, NULL, 'o'},
98 {"dismiss-button", required_argument, NULL, 's'},
64 {"type", required_argument, NULL, 't'}, 99 {"type", required_argument, NULL, 't'},
65 {"version", no_argument, NULL, 'v'}, 100 {"version", no_argument, NULL, 'v'},
66 {0, 0, 0, 0} 101 {0, 0, 0, 0}
@@ -75,26 +110,30 @@ int main(int argc, char **argv) {
75 " -e, --edge top|bottom Set the edge to use.\n" 110 " -e, --edge top|bottom Set the edge to use.\n"
76 " -f, --font <font> Set the font to use.\n" 111 " -f, --font <font> Set the font to use.\n"
77 " -h, --help Show help message and quit.\n" 112 " -h, --help Show help message and quit.\n"
113 " -l, --detailed-message <msg> Set a detailed message.\n"
114 " -L, --detailed-button <text> Set the text of the detail button.\n"
78 " -m, --message <msg> Set the message text.\n" 115 " -m, --message <msg> Set the message text.\n"
79 " -o, --output <output> Set the output to use.\n" 116 " -o, --output <output> Set the output to use.\n"
117 " -s, --dismiss-button <text> Set the dismiss button text.\n"
80 " -t, --type error|warning Set the message type.\n" 118 " -t, --type error|warning Set the message type.\n"
81 " -v, --version Show the version number and quit.\n"; 119 " -v, --version Show the version number and quit.\n";
82 120
83 while (1) { 121 while (1) {
84 int c = getopt_long(argc, argv, "b:de:f:hm:o:t:v", long_options, NULL); 122 int c = getopt_long(argc, argv, "b:de:f:hl:L:m:o:s:t:v", opts, NULL);
85 if (c == -1) { 123 if (c == -1) {
86 break; 124 break;
87 } 125 }
88 switch (c) { 126 switch (c) {
89 case 'b': // Button 127 case 'b': // Button
90 if (optind >= argc) { 128 if (optind >= argc) {
91 fprintf(stderr, "Missing action for button %s", optarg); 129 fprintf(stderr, "Missing action for button %s\n", optarg);
92 exit_code = EXIT_FAILURE; 130 exit_code = EXIT_FAILURE;
93 goto cleanup; 131 goto cleanup;
94 } 132 }
95 struct sway_nagbar_button *button; 133 struct sway_nagbar_button *button;
96 button = calloc(sizeof(struct sway_nagbar_button), 1); 134 button = calloc(sizeof(struct sway_nagbar_button), 1);
97 button->text = strdup(optarg); 135 button->text = strdup(optarg);
136 button->type = NAGBAR_ACTION_COMMAND;
98 button->action = strdup(argv[optind]); 137 button->action = strdup(argv[optind]);
99 optind++; 138 optind++;
100 list_add(nagbar.buttons, button); 139 list_add(nagbar.buttons, button);
@@ -121,6 +160,20 @@ int main(int argc, char **argv) {
121 free(nagbar.font); 160 free(nagbar.font);
122 nagbar.font = strdup(optarg); 161 nagbar.font = strdup(optarg);
123 break; 162 break;
163 case 'l': // Detailed Message
164 free(nagbar.details.message);
165 if (strcmp(optarg, "-") == 0) {
166 nagbar.details.message = read_from_stdin();
167 } else {
168 nagbar.details.message = strdup(optarg);
169 }
170 nagbar.details.button_up.text = strdup("▲");
171 nagbar.details.button_down.text = strdup("▼");
172 break;
173 case 'L': // Detailed Button Text
174 free(button_details->text);
175 button_details->text = strdup(optarg);
176 break;
124 case 'm': // Message 177 case 'm': // Message
125 free(nagbar.message); 178 free(nagbar.message);
126 nagbar.message = strdup(optarg); 179 nagbar.message = strdup(optarg);
@@ -129,13 +182,17 @@ int main(int argc, char **argv) {
129 free(nagbar.output.name); 182 free(nagbar.output.name);
130 nagbar.output.name = strdup(optarg); 183 nagbar.output.name = strdup(optarg);
131 break; 184 break;
185 case 's': // Dismiss Button Text
186 free(button_close->text);
187 button_close->text = strdup(optarg);
188 break;
132 case 't': // Type 189 case 't': // Type
133 if (strcmp(optarg, "error") == 0) { 190 if (strcmp(optarg, "error") == 0) {
134 nagbar.type = NAGBAR_ERROR; 191 nagbar.type = NAGBAR_ERROR;
135 } else if (strcmp(optarg, "warning") == 0) { 192 } else if (strcmp(optarg, "warning") == 0) {
136 nagbar.type = NAGBAR_WARNING; 193 nagbar.type = NAGBAR_WARNING;
137 } else { 194 } else {
138 fprintf(stderr, "Type must be either 'error' or 'warning'"); 195 fprintf(stderr, "Type must be either 'error' or 'warning'\n");
139 exit_code = EXIT_FAILURE; 196 exit_code = EXIT_FAILURE;
140 goto cleanup; 197 goto cleanup;
141 } 198 }
@@ -160,6 +217,13 @@ int main(int argc, char **argv) {
160 goto cleanup; 217 goto cleanup;
161 } 218 }
162 219
220 if (nagbar.details.message) {
221 list_add(nagbar.buttons, button_details);
222 } else {
223 free(button_details->text);
224 free(button_details);
225 }
226
163 wlr_log(WLR_DEBUG, "Output: %s", nagbar.output.name); 227 wlr_log(WLR_DEBUG, "Output: %s", nagbar.output.name);
164 wlr_log(WLR_DEBUG, "Anchors: %d", nagbar.anchors); 228 wlr_log(WLR_DEBUG, "Anchors: %d", nagbar.anchors);
165 wlr_log(WLR_DEBUG, "Type: %d", nagbar.type); 229 wlr_log(WLR_DEBUG, "Type: %d", nagbar.type);
@@ -178,6 +242,8 @@ int main(int argc, char **argv) {
178 return exit_code; 242 return exit_code;
179 243
180cleanup: 244cleanup:
245 free(button_details->text);
246 free(button_details);
181 nagbar_destroy(&nagbar); 247 nagbar_destroy(&nagbar);
182 return exit_code; 248 return exit_code;
183} 249}
diff --git a/swaynagbar/nagbar.c b/swaynagbar/nagbar.c
index 22e5aff4..9e8bbb4b 100644
--- a/swaynagbar/nagbar.c
+++ b/swaynagbar/nagbar.c
@@ -34,8 +34,11 @@ static bool terminal_execute(char *terminal, char *command) {
34static void nagbar_button_execute(struct sway_nagbar *nagbar, 34static void nagbar_button_execute(struct sway_nagbar *nagbar,
35 struct sway_nagbar_button *button) { 35 struct sway_nagbar_button *button) {
36 wlr_log(WLR_DEBUG, "Executing [%s]: %s", button->text, button->action); 36 wlr_log(WLR_DEBUG, "Executing [%s]: %s", button->text, button->action);
37 if (!button->action) { 37 if (button->type == NAGBAR_ACTION_DISMISS) {
38 nagbar->run_display = false; 38 nagbar->run_display = false;
39 } else if (button->type == NAGBAR_ACTION_EXPAND) {
40 nagbar->details.visible = !nagbar->details.visible;
41 render_frame(nagbar);
39 } else { 42 } else {
40 if (fork() == 0) { 43 if (fork() == 0) {
41 // Child process. Will be used to prevent zombie processes 44 // Child process. Will be used to prevent zombie processes
@@ -119,8 +122,58 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
119 && x < nagbutton->x + nagbutton->width 122 && x < nagbutton->x + nagbutton->width
120 && y < nagbutton->y + nagbutton->height) { 123 && y < nagbutton->y + nagbutton->height) {
121 nagbar_button_execute(nagbar, nagbutton); 124 nagbar_button_execute(nagbar, nagbutton);
125 return;
122 } 126 }
123 } 127 }
128
129 if (nagbar->details.visible &&
130 nagbar->details.total_lines != nagbar->details.visible_lines) {
131 struct sway_nagbar_button button_up = nagbar->details.button_up;
132 if (x >= button_up.x
133 && y >= button_up.y
134 && x < button_up.x + button_up.width
135 && y < button_up.y + button_up.height
136 && nagbar->details.offset > 0) {
137 nagbar->details.offset--;
138 render_frame(nagbar);
139 return;
140 }
141
142 struct sway_nagbar_button button_down = nagbar->details.button_down;
143 int bot = nagbar->details.total_lines - nagbar->details.visible_lines;
144 if (x >= button_down.x
145 && y >= button_down.y
146 && x < button_down.x + button_down.width
147 && y < button_down.y + button_down.height
148 && nagbar->details.offset < bot) {
149 nagbar->details.offset++;
150 render_frame(nagbar);
151 return;
152 }
153 }
154}
155
156static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
157 uint32_t time, uint32_t axis, wl_fixed_t value) {
158 struct sway_nagbar *nagbar = data;
159 if (!nagbar->details.visible
160 || nagbar->pointer.x < nagbar->details.x
161 || nagbar->pointer.y < nagbar->details.y
162 || nagbar->pointer.x >= nagbar->details.x + nagbar->details.width
163 || nagbar->pointer.y >= nagbar->details.y + nagbar->details.height
164 || nagbar->details.total_lines == nagbar->details.visible_lines) {
165 return;
166 }
167
168 int direction = wl_fixed_to_int(value);
169 int bot = nagbar->details.total_lines - nagbar->details.visible_lines;
170 if (direction < 0 && nagbar->details.offset > 0) {
171 nagbar->details.offset--;
172 } else if (direction > 0 && nagbar->details.offset < bot) {
173 nagbar->details.offset++;
174 }
175
176 render_frame(nagbar);
124} 177}
125 178
126static struct wl_pointer_listener pointer_listener = { 179static struct wl_pointer_listener pointer_listener = {
@@ -128,7 +181,7 @@ static struct wl_pointer_listener pointer_listener = {
128 .leave = nop, 181 .leave = nop,
129 .motion = wl_pointer_motion, 182 .motion = wl_pointer_motion,
130 .button = wl_pointer_button, 183 .button = wl_pointer_button,
131 .axis = nop, 184 .axis = wl_pointer_axis,
132 .frame = nop, 185 .frame = nop,
133 .axis_source = nop, 186 .axis_source = nop,
134 .axis_stop = nop, 187 .axis_stop = nop,
@@ -329,6 +382,9 @@ void nagbar_destroy(struct sway_nagbar *nagbar) {
329 free(button); 382 free(button);
330 } 383 }
331 list_free(nagbar->buttons); 384 list_free(nagbar->buttons);
385 free(nagbar->details.message);
386 free(nagbar->details.button_up.text);
387 free(nagbar->details.button_down.text);
332 388
333 if (nagbar->layer_surface) { 389 if (nagbar->layer_surface) {
334 zwlr_layer_surface_v1_destroy(nagbar->layer_surface); 390 zwlr_layer_surface_v1_destroy(nagbar->layer_surface);
diff --git a/swaynagbar/render.c b/swaynagbar/render.c
index c0f59298..7bc2961e 100644
--- a/swaynagbar/render.c
+++ b/swaynagbar/render.c
@@ -23,11 +23,149 @@ static uint32_t render_message(cairo_t *cairo, struct sway_nagbar *nagbar) {
23 } 23 }
24 24
25 cairo_set_source_u32(cairo, nagbar->colors.text); 25 cairo_set_source_u32(cairo, nagbar->colors.text);
26 cairo_move_to(cairo, padding, (int)(height / 2.0 - text_height / 2.0)); 26 cairo_move_to(cairo, padding, (int)(ideal_height - text_height) / 2);
27 pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", 27 pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s",
28 nagbar->message); 28 nagbar->message);
29 29
30 return nagbar->height; 30 return ideal_height;
31}
32
33static void render_details_scroll_button(cairo_t *cairo,
34 struct sway_nagbar *nagbar, struct sway_nagbar_button *button) {
35 int text_width, text_height;
36 get_text_size(cairo, nagbar->font, &text_width, &text_height,
37 nagbar->scale, true, "%s", button->text);
38
39 int border = NAGBAR_BUTTON_BORDER_THICKNESS * nagbar->scale;
40 int padding = NAGBAR_BUTTON_PADDING * nagbar->scale;
41
42 cairo_set_source_u32(cairo, nagbar->colors.border);
43 cairo_rectangle(cairo, button->x, button->y,
44 button->width, button->height);
45 cairo_fill(cairo);
46
47 cairo_set_source_u32(cairo, nagbar->colors.button_background);
48 cairo_rectangle(cairo, button->x + border, button->y + border,
49 button->width - (border * 2), button->height - (border * 2));
50 cairo_fill(cairo);
51
52 cairo_set_source_u32(cairo, nagbar->colors.text);
53 cairo_move_to(cairo, button->x + border + padding,
54 button->y + border + (button->height - text_height) / 2);
55 pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", button->text);
56}
57
58static int get_detailed_scroll_button_width(cairo_t *cairo,
59 struct sway_nagbar *nagbar) {
60 int up_width, down_width, temp_height;
61 get_text_size(cairo, nagbar->font, &up_width, &temp_height,
62 nagbar->scale, true, "%s", nagbar->details.button_up.text);
63 get_text_size(cairo, nagbar->font, &down_width, &temp_height,
64 nagbar->scale, true, "%s", nagbar->details.button_down.text);
65
66 int text_width = up_width > down_width ? up_width : down_width;
67 int border = NAGBAR_BUTTON_BORDER_THICKNESS * nagbar->scale;
68 int padding = NAGBAR_BUTTON_PADDING * nagbar->scale;
69
70 return text_width + border * 2 + padding * 2;
71}
72
73static uint32_t render_detailed(cairo_t *cairo, struct sway_nagbar *nagbar,
74 uint32_t y) {
75 uint32_t width = nagbar->width * nagbar->scale;
76 uint32_t height = nagbar->height * nagbar->scale;
77 height -= NAGBAR_BAR_BORDER_THICKNESS * nagbar->scale;
78
79 int border = NAGBAR_DETAILS_BORDER_THICKNESS * nagbar->scale;
80 int padding = NAGBAR_MESSAGE_PADDING * nagbar->scale;
81 int decor = padding + border;
82
83 nagbar->details.x = decor;
84 nagbar->details.y = y + decor;
85 nagbar->details.width = width - decor * 2;
86
87 PangoLayout *layout = get_pango_layout(cairo, nagbar->font,
88 nagbar->details.message, nagbar->scale, true);
89 pango_layout_set_width(layout,
90 (nagbar->details.width - padding * 2) * PANGO_SCALE);
91 pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
92 pango_layout_set_single_paragraph_mode(layout, false);
93 pango_cairo_update_layout(cairo, layout);
94 nagbar->details.total_lines = pango_layout_get_line_count(layout);
95
96 PangoLayoutLine *line;
97 line = pango_layout_get_line_readonly(layout, nagbar->details.offset);
98 gint offset = line->start_index;
99 const char *text = pango_layout_get_text(layout);
100 pango_layout_set_text(layout, text + offset, strlen(text) - offset);
101
102 int text_width, text_height;
103 pango_cairo_update_layout(cairo, layout);
104 pango_layout_get_pixel_size(layout, &text_width, &text_height);
105
106 bool show_buttons = nagbar->details.offset > 0;
107 int button_width = get_detailed_scroll_button_width(cairo, nagbar);
108 if (show_buttons) {
109 nagbar->details.width -= button_width;
110 pango_layout_set_width(layout,
111 (nagbar->details.width - padding * 2) * PANGO_SCALE);
112 }
113
114 uint32_t ideal_height;
115 do {
116 ideal_height = nagbar->details.y + text_height + decor + padding * 2;
117 if (ideal_height > NAGBAR_MAX_HEIGHT) {
118 ideal_height = NAGBAR_MAX_HEIGHT;
119
120 if (!show_buttons) {
121 show_buttons = true;
122 nagbar->details.width -= button_width;
123 pango_layout_set_width(layout,
124 (nagbar->details.width - padding * 2) * PANGO_SCALE);
125 }
126 }
127
128 nagbar->details.height = ideal_height - nagbar->details.y - decor;
129 pango_layout_set_height(layout,
130 (nagbar->details.height - padding * 2) * PANGO_SCALE);
131 pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
132 pango_cairo_update_layout(cairo, layout);
133 pango_layout_get_pixel_size(layout, &text_width, &text_height);
134 } while (text_height != (nagbar->details.height - padding * 2));
135
136 nagbar->details.visible_lines = pango_layout_get_line_count(layout);
137
138 if (show_buttons) {
139 nagbar->details.button_up.x =
140 nagbar->details.x + nagbar->details.width;
141 nagbar->details.button_up.y = nagbar->details.y;
142 nagbar->details.button_up.width = button_width;
143 nagbar->details.button_up.height = nagbar->details.height / 2;
144 render_details_scroll_button(cairo, nagbar,
145 &nagbar->details.button_up);
146
147 nagbar->details.button_down.x =
148 nagbar->details.x + nagbar->details.width;
149 nagbar->details.button_down.y =
150 nagbar->details.button_up.y + nagbar->details.button_up.height;
151 nagbar->details.button_down.width = button_width;
152 nagbar->details.button_down.height = nagbar->details.height / 2;
153 render_details_scroll_button(cairo, nagbar,
154 &nagbar->details.button_down);
155 }
156
157 cairo_set_source_u32(cairo, nagbar->colors.border);
158 cairo_rectangle(cairo, nagbar->details.x, nagbar->details.y,
159 nagbar->details.width, nagbar->details.height);
160 cairo_fill(cairo);
161
162 cairo_move_to(cairo, nagbar->details.x + padding,
163 nagbar->details.y + padding);
164 cairo_set_source_u32(cairo, nagbar->colors.text);
165 pango_cairo_show_layout(cairo, layout);
166 g_object_unref(layout);
167
168 return ideal_height;
31} 169}
32 170
33static uint32_t render_button(cairo_t *cairo, struct sway_nagbar *nagbar, 171static uint32_t render_button(cairo_t *cairo, struct sway_nagbar *nagbar,
@@ -50,7 +188,7 @@ static uint32_t render_button(cairo_t *cairo, struct sway_nagbar *nagbar,
50 } 188 }
51 189
52 button->x = *x - border - text_width - padding * 2; 190 button->x = *x - border - text_width - padding * 2;
53 button->y = (int)(height / 2.0 - text_height / 2.0) - padding; 191 button->y = (int)(ideal_height - text_height) / 2 - padding;
54 button->width = text_width + padding * 2; 192 button->width = text_width + padding * 2;
55 button->height = text_height + padding * 2; 193 button->height = text_height + padding * 2;
56 194
@@ -70,7 +208,7 @@ static uint32_t render_button(cairo_t *cairo, struct sway_nagbar *nagbar,
70 208
71 *x = button->x - border; 209 *x = button->x - border;
72 210
73 return nagbar->height; 211 return ideal_height;
74} 212}
75 213
76static uint32_t render_to_cairo(cairo_t *cairo, struct sway_nagbar *nagbar) { 214static uint32_t render_to_cairo(cairo_t *cairo, struct sway_nagbar *nagbar) {
@@ -93,6 +231,11 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct sway_nagbar *nagbar) {
93 } 231 }
94 } 232 }
95 233
234 if (nagbar->details.visible) {
235 h = render_detailed(cairo, nagbar, max_height);
236 max_height = h > max_height ? h : max_height;
237 }
238
96 int border = NAGBAR_BAR_BORDER_THICKNESS * nagbar->scale; 239 int border = NAGBAR_BAR_BORDER_THICKNESS * nagbar->scale;
97 if (max_height > nagbar->height) { 240 if (max_height > nagbar->height) {
98 max_height += border; 241 max_height += border;
@@ -102,7 +245,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct sway_nagbar *nagbar) {
102 nagbar->width * nagbar->scale, border); 245 nagbar->width * nagbar->scale, border);
103 cairo_fill(cairo); 246 cairo_fill(cairo);
104 247
105 return max_height > nagbar->height ? max_height : nagbar->height; 248 return max_height;
106} 249}
107 250
108void render_frame(struct sway_nagbar *nagbar) { 251void render_frame(struct sway_nagbar *nagbar) {
@@ -129,13 +272,16 @@ void render_frame(struct sway_nagbar *nagbar) {
129 nagbar->buffers, 272 nagbar->buffers,
130 nagbar->width * nagbar->scale, 273 nagbar->width * nagbar->scale,
131 nagbar->height * nagbar->scale); 274 nagbar->height * nagbar->scale);
132 cairo_t *shm = nagbar->current_buffer->cairo; 275 if (!nagbar->current_buffer) {
276 wlr_log(WLR_DEBUG, "Failed to get buffer. Skipping frame.");
277 return;
278 }
133 279
280 cairo_t *shm = nagbar->current_buffer->cairo;
134 cairo_save(shm); 281 cairo_save(shm);
135 cairo_set_operator(shm, CAIRO_OPERATOR_CLEAR); 282 cairo_set_operator(shm, CAIRO_OPERATOR_CLEAR);
136 cairo_paint(shm); 283 cairo_paint(shm);
137 cairo_restore(shm); 284 cairo_restore(shm);
138
139 cairo_set_source_surface(shm, recorder, 0.0, 0.0); 285 cairo_set_source_surface(shm, recorder, 0.0, 0.0);
140 cairo_paint(shm); 286 cairo_paint(shm);
141 287
diff --git a/swaynagbar/swaynagbar.1.scd b/swaynagbar/swaynagbar.1.scd
index 4235e2ea..2a34ae68 100644
--- a/swaynagbar/swaynagbar.1.scd
+++ b/swaynagbar/swaynagbar.1.scd
@@ -25,6 +25,15 @@ _swaynagbar_ [options...]
25*-h, --help* 25*-h, --help*
26 Show help message and quit. 26 Show help message and quit.
27 27
28*-l, --detailed-message <msg>*
29 Set the detailed message. A button to toggle details will be added. Details
30 are shown in a scrollable multi-line text area. If _msg_ is _-_, then the
31 detailed message will be read from stdin.
32
33*-L, --detailed-button <text>*
34 Set the text for the button that toggles details. This has no effect if
35 there is not a detailed message. The default is _Toggle Details_.
36
28*-m, --message <msg>* 37*-m, --message <msg>*
29 Set the message text. 38 Set the message text.
30 39
@@ -33,6 +42,9 @@ _swaynagbar_ [options...]
33 _xdg\_output\_manager_ is not supported, then the first detected output 42 _xdg\_output\_manager_ is not supported, then the first detected output
34 will be used 43 will be used
35 44
45*-s, --dismiss-button <text>*
46 Sets the text for the dismiss nagbar button. The default is _X_.
47
36*-t, --type error|warning* 48*-t, --type error|warning*
37 Set the message type. 49 Set the message type.
38 50