summaryrefslogtreecommitdiffstats
path: root/sway/border.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/border.c')
-rw-r--r--sway/border.c297
1 files changed, 226 insertions, 71 deletions
diff --git a/sway/border.c b/sway/border.c
index a6ed4238..cec443f4 100644
--- a/sway/border.c
+++ b/sway/border.c
@@ -11,37 +11,40 @@
11#include <arpa/inet.h> 11#include <arpa/inet.h>
12 12
13void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { 13void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
14 color = htonl(color); 14 color = htonl(color);
15 15
16 cairo_set_source_rgba(cairo, 16 cairo_set_source_rgba(cairo,
17 (color >> (2*8) & 0xFF) / 255.0, 17 (color >> (2*8) & 0xFF) / 255.0,
18 (color >> (1*8) & 0xFF) / 255.0, 18 (color >> (1*8) & 0xFF) / 255.0,
19 (color >> (0*8) & 0xFF) / 255.0, 19 (color >> (0*8) & 0xFF) / 255.0,
20 (color >> (3*8) & 0xFF) / 255.0); 20 (color >> (3*8) & 0xFF) / 255.0);
21} 21}
22 22
23static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry geo, cairo_surface_t **surface) { 23static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry g, cairo_surface_t **surface) {
24 if (view->border == NULL) {
25 view->border = malloc(sizeof(struct border));
26 }
24 cairo_t *cr; 27 cairo_t *cr;
25 view->border_geometry = geo; 28 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, g.size.w);
26 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, geo.size.w); 29 view->border->buffer = calloc(stride * g.size.h, sizeof(unsigned char));
27 view->border = calloc(stride * geo.size.h, sizeof(unsigned char)); 30 view->border->geometry = g;
28 if (!view->border) { 31 if (!view->border->buffer) {
29 sway_log(L_DEBUG, "Unable to allocate buffer"); 32 sway_log(L_DEBUG, "Unable to allocate buffer");
30 return NULL; 33 return NULL;
31 } 34 }
32 *surface = cairo_image_surface_create_for_data(view->border, 35 *surface = cairo_image_surface_create_for_data(view->border->buffer,
33 CAIRO_FORMAT_ARGB32, geo.size.w, geo.size.h, stride); 36 CAIRO_FORMAT_ARGB32, g.size.w, g.size.h, stride);
34 if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) { 37 if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) {
35 free(view->border); 38 free(view->border);
36 view->border = NULL; 39 view->border->buffer = NULL;
37 sway_log(L_DEBUG, "Unable to allocate surface"); 40 sway_log(L_DEBUG, "Unable to allocate surface");
38 return NULL; 41 return NULL;
39 } 42 }
40 cr = cairo_create(*surface); 43 cr = cairo_create(*surface);
41 if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) { 44 if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
42 cairo_surface_destroy(*surface); 45 cairo_surface_destroy(*surface);
43 free(view->border); 46 free(view->border->buffer);
44 view->border = NULL; 47 view->border->buffer = NULL;
45 sway_log(L_DEBUG, "Unable to create cairo context"); 48 sway_log(L_DEBUG, "Unable to create cairo context");
46 return NULL; 49 return NULL;
47 } 50 }
@@ -91,16 +94,20 @@ int get_font_text_height(const char *font) {
91 return height; 94 return height;
92} 95}
93 96
94static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors) { 97static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors, bool top) {
98 struct wlc_geometry *g = &view->border->geometry;
95 struct wlc_geometry *b = &view->border_geometry; 99 struct wlc_geometry *b = &view->border_geometry;
96 struct wlc_geometry *v = &view->actual_geometry; 100 struct wlc_geometry *v = &view->actual_geometry;
97 101
102 int x = b->origin.x - g->origin.x;
103 int y = b->origin.y - g->origin.y;
104
98 // left border 105 // left border
99 int left_border = v->origin.x - b->origin.x; 106 int left_border = v->origin.x - b->origin.x;
100 if (left_border > 0) { 107 if (left_border > 0) {
101 render_sharp_line(cr, 108 render_sharp_line(cr,
102 colors->child_border, 109 colors->child_border,
103 0, 0, 110 x, y,
104 left_border, 111 left_border,
105 b->size.h); 112 b->size.h);
106 } 113 }
@@ -110,18 +117,18 @@ static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *col
110 if (right_border > 0) { 117 if (right_border > 0) {
111 render_sharp_line(cr, 118 render_sharp_line(cr,
112 colors->child_border, 119 colors->child_border,
113 b->size.w - right_border, 120 x + b->size.w - right_border,
114 0, 121 y,
115 right_border, 122 right_border,
116 b->size.h); 123 b->size.h);
117 } 124 }
118 125
119 // top border 126 // top border
120 int top_border = v->origin.y - b->origin.y; 127 int top_border = v->origin.y - b->origin.y;
121 if (top_border > 0) { 128 if (top && top_border > 0) {
122 render_sharp_line(cr, 129 render_sharp_line(cr,
123 colors->child_border, 130 colors->child_border,
124 0, 0, 131 x, y,
125 b->size.w, 132 b->size.w,
126 top_border); 133 top_border);
127 } 134 }
@@ -131,45 +138,63 @@ static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *col
131 if (bottom_border > 0) { 138 if (bottom_border > 0) {
132 render_sharp_line(cr, 139 render_sharp_line(cr,
133 colors->child_border, 140 colors->child_border,
134 0, 141 x,
135 b->size.h - bottom_border, 142 y + b->size.h - bottom_border,
136 b->size.w, 143 b->size.w,
137 bottom_border); 144 bottom_border);
138 } 145 }
139} 146}
140 147
141static void render_with_title_bar(swayc_t *view, cairo_t *cr, struct border_colors *colors) { 148static void render_title_bar(swayc_t *view, cairo_t *cr, struct wlc_geometry *b, struct border_colors *colors) {
142 struct wlc_geometry *tb = &view->title_bar_geometry; 149 struct wlc_geometry *tb = &view->title_bar_geometry;
143 struct wlc_geometry *b = &view->border_geometry; 150 int x = MIN(tb->origin.x, tb->origin.x - b->origin.x);
144 int title_y = MIN(view->actual_geometry.origin.y - (int)tb->size.h, 0); 151 int y = MIN(tb->origin.y, tb->origin.y - b->origin.y);
145
146 // borders
147 render_borders(view, cr, colors);
148 152
149 // title bar background 153 // title bar background
150 cairo_set_source_u32(cr, colors->background); 154 cairo_set_source_u32(cr, colors->background);
151 cairo_rectangle(cr, 0, title_y, tb->size.w, tb->size.h); 155 cairo_rectangle(cr, x, y, tb->size.w, tb->size.h);
152 cairo_fill(cr); 156 cairo_fill(cr);
153 157
154 // header top line 158 // header top line
155 render_sharp_line(cr, colors->border, 0, title_y, tb->size.w, 1); 159 render_sharp_line(cr, colors->border, x, y, tb->size.w, 1);
156 160
157 // text 161 // text
158 if (view->name) { 162 if (view->name) {
159 int width, height; 163 int width, height;
160 get_text_size(cr, config->font, &width, &height, false, "%s", view->name); 164 get_text_size(cr, config->font, &width, &height, false, "%s", view->name);
161 int x = MIN(view->actual_geometry.origin.x, view->border_thickness); 165 cairo_move_to(cr, x + 2, y + 2);
162 int y = MIN(view->actual_geometry.origin.y - height - 2, 2);
163 cairo_move_to(cr, x, y);
164 cairo_set_source_u32(cr, colors->text); 166 cairo_set_source_u32(cr, colors->text);
165 pango_printf(cr, config->font, false, "%s", view->name); 167 pango_printf(cr, config->font, false, "%s", view->name);
166 } 168 }
167 169
168 // header bottom line 170 // titlebars has a border all around for tabbed layouts
169 render_sharp_line(cr, colors->border, 171 if (view->parent->layout == L_TABBED) {
170 view->actual_geometry.origin.x - b->origin.x, 172 // header bottom line
171 title_y + tb->size.h - 1, 173 render_sharp_line(cr, colors->border, x, y + tb->size.h - 1,
172 view->actual_geometry.size.w, 1); 174 tb->size.w, 1);
175
176 // left border
177 render_sharp_line(cr, colors->border, x, y, 1, tb->size.h);
178
179 // right border
180 render_sharp_line(cr, colors->border, x + tb->size.w - 1, y,
181 1, tb->size.h);
182
183 return;
184 }
185
186 if ((uint32_t)(view->actual_geometry.origin.y - tb->origin.y) == tb->size.h) {
187 // header bottom line
188 render_sharp_line(cr, colors->border,
189 x + view->actual_geometry.origin.x - tb->origin.x,
190 y + tb->size.h - 1,
191 view->actual_geometry.size.w, 1);
192 } else {
193 // header bottom line
194 render_sharp_line(cr, colors->border, x,
195 y + tb->size.h - 1,
196 tb->size.w, 1);
197 }
173} 198}
174 199
175void map_update_view_border(swayc_t *view, void *data) { 200void map_update_view_border(swayc_t *view, void *data) {
@@ -178,15 +203,104 @@ void map_update_view_border(swayc_t *view, void *data) {
178 } 203 }
179} 204}
180 205
206/**
207 * Generate nested container title for tabbed/stacked layouts
208 */
209static char *generate_container_title(swayc_t *container) {
210 char layout = 'H';
211 char *name, *prev_name = NULL;
212 switch (container->layout) {
213 case L_TABBED:
214 layout = 'T';
215 break;
216 case L_STACKED:
217 layout = 'S';
218 break;
219 case L_VERT:
220 layout = 'V';
221 break;
222 default:
223 layout = 'H';
224 }
225 int len = 9;
226 name = malloc(len * sizeof(char));
227 snprintf(name, len, "sway: %c[", layout);
228
229 int i;
230 for (i = 0; i < container->children->length; ++i) {
231 prev_name = name;
232 swayc_t* child = container->children->items[i];
233 const char *title = child->name;
234 if (child->type == C_CONTAINER) {
235 title = generate_container_title(child);
236 }
237
238 len = strlen(name) + strlen(title) + 1;
239 if (i < container->children->length-1) {
240 len++;
241 }
242
243 name = malloc(len * sizeof(char));
244 if (i < container->children->length-1) {
245 snprintf(name, len, "%s%s ", prev_name, title);
246 } else {
247 snprintf(name, len, "%s%s", prev_name, title);
248 }
249 free(prev_name);
250 }
251
252 prev_name = name;
253 len = strlen(name) + 2;
254 name = malloc(len * sizeof(char));
255 snprintf(name, len, "%s]", prev_name);
256 free(prev_name);
257 free(container->name);
258 container->name = name;
259 return container->name + 6; // don't include "sway: "
260}
261
262void update_tabbed_stacked_titlebars(swayc_t *c, cairo_t *cr, struct wlc_geometry *g, swayc_t *focused, swayc_t *focused_inactive) {
263 if (c->type == C_CONTAINER) {
264 if (c->parent->focused == c) {
265 render_title_bar(c, cr, g, &config->border_colors.focused_inactive);
266 } else {
267 render_title_bar(c, cr, g, &config->border_colors.unfocused);
268 }
269
270 if (!c->visible) {
271 return;
272 }
273
274 int i;
275 for (i = 0; i < c->children->length; ++i) {
276 swayc_t *child = c->children->items[i];
277 update_tabbed_stacked_titlebars(child, cr, g, focused, focused_inactive);
278 }
279 } else {
280 if (focused == c) {
281 render_title_bar(c, cr, g, &config->border_colors.focused);
282 } else if (focused_inactive == c) {
283 render_title_bar(c, cr, g, &config->border_colors.focused_inactive);
284 } else {
285 render_title_bar(c, cr, g, &config->border_colors.unfocused);
286 }
287 }
288}
289
181void update_view_border(swayc_t *view) { 290void update_view_border(swayc_t *view) {
291 if (!view->visible) {
292 return;
293 }
294
182 cairo_t *cr = NULL; 295 cairo_t *cr = NULL;
183 cairo_surface_t *surface = NULL; 296 cairo_surface_t *surface = NULL;
184 297
185 if (view->border) { 298 if (view->border && view->border->buffer) {
186 free(view->border); 299 free(view->border->buffer);
187 view->border = NULL; 300 view->border->buffer = NULL;
188 } 301 }
189 302
303 // get focused and focused_inactive views
190 swayc_t *focused = get_focused_view(&root_container); 304 swayc_t *focused = get_focused_view(&root_container);
191 swayc_t *container = swayc_parent_by_type(view, C_CONTAINER); 305 swayc_t *container = swayc_parent_by_type(view, C_CONTAINER);
192 swayc_t *focused_inactive = NULL; 306 swayc_t *focused_inactive = NULL;
@@ -199,44 +313,85 @@ void update_view_border(swayc_t *view) {
199 } 313 }
200 } 314 }
201 315
202 switch (view->border_type) { 316 // for tabbed/stacked layouts the focused view has to draw all the
203 case B_NONE: 317 // titlebars of the hidden views.
204 break; 318 swayc_t *p = swayc_tabbed_stacked_parent(view);
205 case B_PIXEL: 319 if (p && view->parent->focused == view) {
206 cr = create_border_buffer(view, view->border_geometry, &surface); 320 struct wlc_geometry g = {
207 if (!cr) { 321 .origin = {
208 break; 322 .x = p->x,
323 .y = p->y
324 },
325 .size = {
326 .w = p->width,
327 .h = p->height
328 }
329 };
330 cr = create_border_buffer(view, g, &surface);
331 if (view == focused) {
332 render_borders(view, cr, &config->border_colors.focused, false);
333 } else {
334 render_borders(view, cr, &config->border_colors.focused_inactive, false);
209 } 335 }
210 336
211 if (focused == view) { 337 // generate container titles
212 render_borders(view, cr, &config->border_colors.focused); 338 int i;
213 } else if (focused_inactive == view) { 339 for (i = 0; i < p->children->length; ++i) {
214 render_borders(view, cr, &config->border_colors.focused_inactive); 340 swayc_t *child = p->children->items[i];
215 } else { 341 if (child->type == C_CONTAINER) {
216 render_borders(view, cr, &config->border_colors.unfocused); 342 generate_container_title(child);
343 }
217 } 344 }
218 345
219 break; 346 update_tabbed_stacked_titlebars(p, cr, &g, focused, focused_inactive);
220 case B_NORMAL: 347 } else {
221 cr = create_border_buffer(view, view->border_geometry, &surface); 348 switch (view->border_type) {
222 if (!cr) { 349 case B_NONE:
223 break; 350 break;
224 } 351 case B_PIXEL:
352 cr = create_border_buffer(view, view->border_geometry, &surface);
353 if (!cr) {
354 break;
355 }
225 356
226 if (focused == view) { 357 if (focused == view) {
227 render_with_title_bar(view, cr, &config->border_colors.focused); 358 render_borders(view, cr, &config->border_colors.focused, true);
228 } else if (focused_inactive == view) { 359 } else if (focused_inactive == view) {
229 render_with_title_bar(view, cr, &config->border_colors.focused_inactive); 360 render_borders(view, cr, &config->border_colors.focused_inactive, true);
230 } else { 361 } else {
231 render_with_title_bar(view, cr, &config->border_colors.unfocused); 362 render_borders(view, cr, &config->border_colors.unfocused, true);
232 } 363 }
233 364
234 break; 365 break;
366 case B_NORMAL:
367 cr = create_border_buffer(view, view->border_geometry, &surface);
368 if (!cr) {
369 break;
370 }
371
372 if (focused == view) {
373 render_borders(view, cr, &config->border_colors.focused, false);
374 render_title_bar(view, cr, &view->border_geometry,
375 &config->border_colors.focused);
376 } else if (focused_inactive == view) {
377 render_borders(view, cr, &config->border_colors.focused_inactive, false);
378 render_title_bar(view, cr, &view->border_geometry,
379 &config->border_colors.focused_inactive);
380 } else {
381 render_borders(view, cr, &config->border_colors.unfocused, false);
382 render_title_bar(view, cr, &view->border_geometry,
383 &config->border_colors.unfocused);
384 }
385
386 break;
387 }
235 } 388 }
389
236 if (surface) { 390 if (surface) {
237 cairo_surface_flush(surface); 391 cairo_surface_flush(surface);
238 cairo_surface_destroy(surface); 392 cairo_surface_destroy(surface);
239 } 393 }
394
240 if (cr) { 395 if (cr) {
241 cairo_destroy(cr); 396 cairo_destroy(cr);
242 } 397 }
@@ -262,7 +417,7 @@ void render_view_borders(wlc_handle view) {
262 } 417 }
263 } 418 }
264 419
265 if (c->border) { 420 if (c->border && c->border->buffer) {
266 wlc_pixels_write(WLC_RGBA8888, &c->border_geometry, c->border); 421 wlc_pixels_write(WLC_RGBA8888, &c->border->geometry, c->border->buffer);
267 } 422 }
268} 423}