summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/stringop.c14
-rw-r--r--include/stringop.h5
-rw-r--r--include/sway/tree/container.h17
-rw-r--r--include/swaylock/swaylock.h15
-rw-r--r--sway/commands/layout.c3
-rw-r--r--sway/desktop/output.c602
-rw-r--r--sway/input/cursor.c4
-rw-r--r--sway/ipc-server.c22
-rw-r--r--sway/tree/arrange.c33
-rw-r--r--sway/tree/container.c115
-rw-r--r--sway/tree/layout.c44
-rw-r--r--sway/tree/view.c68
-rw-r--r--swaylock/main.c99
-rw-r--r--swaylock/render.c3
14 files changed, 559 insertions, 485 deletions
diff --git a/common/stringop.c b/common/stringop.c
index 4a37543d..d9ae9925 100644
--- a/common/stringop.c
+++ b/common/stringop.c
@@ -55,6 +55,20 @@ void strip_quotes(char *str) {
55 *end = '\0'; 55 *end = '\0';
56} 56}
57 57
58char *lenient_strcat(char *dest, const char *src) {
59 if (dest && src) {
60 return strcat(dest, src);
61 }
62 return dest;
63}
64
65char *lenient_strncat(char *dest, const char *src, size_t len) {
66 if (dest && src) {
67 return strncat(dest, src, len);
68 }
69 return dest;
70}
71
58// strcmp that also handles null pointers. 72// strcmp that also handles null pointers.
59int lenient_strcmp(char *a, char *b) { 73int lenient_strcmp(char *a, char *b) {
60 if (a == b) { 74 if (a == b) {
diff --git a/include/stringop.h b/include/stringop.h
index 7c29a745..e7f58011 100644
--- a/include/stringop.h
+++ b/include/stringop.h
@@ -1,5 +1,6 @@
1#ifndef _SWAY_STRINGOP_H 1#ifndef _SWAY_STRINGOP_H
2#define _SWAY_STRINGOP_H 2#define _SWAY_STRINGOP_H
3#include <stdlib.h>
3#include "list.h" 4#include "list.h"
4 5
5#if !HAVE_DECL_SETENV 6#if !HAVE_DECL_SETENV
@@ -14,6 +15,10 @@ char *strip_whitespace(char *str);
14char *strip_comments(char *str); 15char *strip_comments(char *str);
15void strip_quotes(char *str); 16void strip_quotes(char *str);
16 17
18// strcat that does nothing if dest or src is NULL
19char *lenient_strcat(char *dest, const char *src);
20char *lenient_strncat(char *dest, const char *src, size_t len);
21
17// strcmp that also handles null pointers. 22// strcmp that also handles null pointers.
18int lenient_strcmp(char *a, char *b); 23int lenient_strcmp(char *a, char *b);
19 24
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 598a4f3d..a5f591ce 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -11,6 +11,12 @@ extern struct sway_container root_container;
11struct sway_view; 11struct sway_view;
12struct sway_seat; 12struct sway_seat;
13 13
14#define TITLEBAR_BORDER_THICKNESS 1
15
16// Padding includes titlebar border
17#define TITLEBAR_H_PADDING 3
18#define TITLEBAR_V_PADDING 4
19
14/** 20/**
15 * Different kinds of containers. 21 * Different kinds of containers.
16 * 22 *
@@ -210,6 +216,15 @@ void container_update_title_textures(struct sway_container *container);
210 */ 216 */
211void container_calculate_title_height(struct sway_container *container); 217void container_calculate_title_height(struct sway_container *container);
212 218
213void container_notify_child_title_changed(struct sway_container *container); 219/**
220 * Notify a container that a tree modification has changed in its children,
221 * so the container can update its tree representation.
222 */
223void container_notify_subtree_changed(struct sway_container *container);
224
225/**
226 * Return the height of a regular title bar.
227 */
228size_t container_titlebar_height(void);
214 229
215#endif 230#endif
diff --git a/include/swaylock/swaylock.h b/include/swaylock/swaylock.h
index e161ada9..dae823b8 100644
--- a/include/swaylock/swaylock.h
+++ b/include/swaylock/swaylock.h
@@ -10,13 +10,13 @@
10#include "wlr-layer-shell-unstable-v1-client-protocol.h" 10#include "wlr-layer-shell-unstable-v1-client-protocol.h"
11 11
12enum auth_state { 12enum auth_state {
13 AUTH_STATE_IDLE, 13 AUTH_STATE_IDLE,
14 AUTH_STATE_CLEAR, 14 AUTH_STATE_CLEAR,
15 AUTH_STATE_INPUT, 15 AUTH_STATE_INPUT,
16 AUTH_STATE_INPUT_NOP, 16 AUTH_STATE_INPUT_NOP,
17 AUTH_STATE_BACKSPACE, 17 AUTH_STATE_BACKSPACE,
18 AUTH_STATE_VALIDATING, 18 AUTH_STATE_VALIDATING,
19 AUTH_STATE_INVALID, 19 AUTH_STATE_INVALID,
20}; 20};
21 21
22struct swaylock_args { 22struct swaylock_args {
@@ -50,6 +50,7 @@ struct swaylock_surface {
50 cairo_surface_t *image; 50 cairo_surface_t *image;
51 struct swaylock_state *state; 51 struct swaylock_state *state;
52 struct wl_output *output; 52 struct wl_output *output;
53 uint32_t output_global_name;
53 struct zxdg_output_v1 *xdg_output; 54 struct zxdg_output_v1 *xdg_output;
54 struct wl_surface *surface; 55 struct wl_surface *surface;
55 struct zwlr_layer_surface_v1 *layer_surface; 56 struct zwlr_layer_surface_v1 *layer_surface;
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index 8aa321ae..6b44b001 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -41,6 +41,8 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
41 parent->layout = L_VERT; 41 parent->layout = L_VERT;
42 } else if (strcasecmp(argv[0], "tabbed") == 0) { 42 } else if (strcasecmp(argv[0], "tabbed") == 0) {
43 parent->layout = L_TABBED; 43 parent->layout = L_TABBED;
44 } else if (strcasecmp(argv[0], "stacking") == 0) {
45 parent->layout = L_STACKED;
44 } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { 46 } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
45 if (parent->layout == L_HORIZ) { 47 if (parent->layout == L_HORIZ) {
46 parent->layout = L_VERT; 48 parent->layout = L_VERT;
@@ -50,6 +52,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
50 } 52 }
51 } 53 }
52 54
55 container_notify_subtree_changed(parent);
53 arrange_children_of(parent); 56 arrange_children_of(parent);
54 57
55 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 58 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 551e96fc..765647fd 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -269,17 +269,6 @@ static void render_unmanaged(struct sway_output *output,
269 render_surface_iterator, &data); 269 render_surface_iterator, &data);
270} 270}
271 271
272static void render_view(struct sway_view *view, struct sway_output *output,
273 pixman_region32_t *damage) {
274 struct render_data data = {
275 .output = output,
276 .damage = damage,
277 .alpha = view->swayc->alpha,
278 };
279 output_view_for_each_surface(
280 view, &data.root_geo, render_surface_iterator, &data);
281}
282
283static void render_rect(struct wlr_output *wlr_output, 272static void render_rect(struct wlr_output *wlr_output,
284 pixman_region32_t *output_damage, const struct wlr_box *_box, 273 pixman_region32_t *output_damage, const struct wlr_box *_box,
285 float color[static 4]) { 274 float color[static 4]) {
@@ -317,108 +306,161 @@ static void premultiply_alpha(float color[4], float opacity) {
317 color[2] *= color[3]; 306 color[2] *= color[3];
318} 307}
319 308
309static void render_view_surfaces(struct sway_view *view,
310 struct sway_output *output, pixman_region32_t *damage) {
311 struct render_data data = {
312 .output = output,
313 .damage = damage,
314 .alpha = view->swayc->alpha,
315 };
316 output_view_for_each_surface(
317 view, &data.root_geo, render_surface_iterator, &data);
318}
319
320/** 320/**
321 * Render decorations for a view with "border normal". 321 * Render a view's surface and left/bottom/right borders.
322 *
323 * Care must be taken not to render over the same pixel multiple times,
324 * otherwise the colors will be incorrect when using opacity.
325 */ 322 */
326static void render_container_simple_border_normal(struct sway_output *output, 323static void render_view(struct sway_output *output, pixman_region32_t *damage,
327 pixman_region32_t *output_damage, 324 struct sway_container *con, struct border_colors *colors) {
328 struct sway_container *con, struct border_colors *colors,
329 struct wlr_texture *title_texture, struct wlr_texture *marks_texture) {
330 struct wlr_box box;
331 float color[4];
332 struct sway_view *view = con->sway_view; 325 struct sway_view *view = con->sway_view;
333 float output_scale = output->wlr_output->scale; 326 render_view_surfaces(view, output, damage);
334 327
335 if (view->border_left) { 328 struct wlr_box box;
336 // Child border - left edge 329 float output_scale = output->wlr_output->scale;
337 memcpy(&color, colors->child_border, sizeof(float) * 4); 330 float color[4];
338 premultiply_alpha(color, con->alpha);
339 box.x = con->x;
340 box.y = con->y + 1;
341 box.width = view->border_thickness;
342 box.height = con->height - 1
343 - view->border_thickness * view->border_bottom;
344 scale_box(&box, output_scale);
345 render_rect(output->wlr_output, output_damage, &box, color);
346 }
347 331
348 if (view->border_right) { 332 if (view->border != B_NONE) {
349 // Child border - right edge 333 if (view->border_left) {
350 if (con->parent->children->length == 1
351 && con->parent->layout == L_HORIZ) {
352 memcpy(&color, colors->indicator, sizeof(float) * 4);
353 } else {
354 memcpy(&color, colors->child_border, sizeof(float) * 4); 334 memcpy(&color, colors->child_border, sizeof(float) * 4);
335 premultiply_alpha(color, con->alpha);
336 box.x = con->x;
337 box.y = view->y;
338 box.width = view->border_thickness;
339 box.height = view->height;
340 scale_box(&box, output_scale);
341 render_rect(output->wlr_output, damage, &box, color);
355 } 342 }
356 premultiply_alpha(color, con->alpha);
357 box.x = con->x + con->width - view->border_thickness;
358 box.y = con->y + 1;
359 box.width = view->border_thickness;
360 box.height = con->height - 1
361 - view->border_thickness * view->border_bottom;
362 scale_box(&box, output_scale);
363 render_rect(output->wlr_output, output_damage, &box, color);
364 }
365 343
366 if (view->border_bottom) { 344 if (view->border_right) {
367 // Child border - bottom edge 345 if (con->parent->children->length == 1
368 if (con->parent->children->length == 1 346 && con->parent->layout == L_HORIZ) {
369 && con->parent->layout == L_VERT) { 347 memcpy(&color, colors->indicator, sizeof(float) * 4);
370 memcpy(&color, colors->indicator, sizeof(float) * 4); 348 } else {
371 } else { 349 memcpy(&color, colors->child_border, sizeof(float) * 4);
372 memcpy(&color, colors->child_border, sizeof(float) * 4); 350 }
351 premultiply_alpha(color, con->alpha);
352 box.x = view->x + view->width;
353 box.y = view->y;
354 box.width = view->border_thickness;
355 box.height = view->height;
356 scale_box(&box, output_scale);
357 render_rect(output->wlr_output, damage, &box, color);
358 }
359
360 if (view->border_bottom) {
361 if (con->parent->children->length == 1
362 && con->parent->layout == L_VERT) {
363 memcpy(&color, colors->indicator, sizeof(float) * 4);
364 } else {
365 memcpy(&color, colors->child_border, sizeof(float) * 4);
366 }
367 premultiply_alpha(color, con->alpha);
368 box.x = con->x;
369 box.y = view->y + view->height;
370 box.width = con->width;
371 box.height = view->border_thickness;
372 scale_box(&box, output_scale);
373 render_rect(output->wlr_output, damage, &box, color);
373 } 374 }
374 premultiply_alpha(color, con->alpha);
375 box.x = con->x;
376 box.y = con->y + con->height - view->border_thickness;
377 box.width = con->width;
378 box.height = view->border_thickness;
379 scale_box(&box, output_scale);
380 render_rect(output->wlr_output, output_damage, &box, color);
381 } 375 }
376}
377
378/**
379 * Render a titlebar.
380 *
381 * Care must be taken not to render over the same pixel multiple times,
382 * otherwise the colors will be incorrect when using opacity.
383 *
384 * The height is: 1px border, 3px padding, font height, 3px padding, 1px border
385 * The left side for L_TABBED is: 1px border, 2px padding, title
386 * The left side for other layouts is: 3px padding, title
387 */
388static void render_titlebar(struct sway_output *output,
389 pixman_region32_t *output_damage, struct sway_container *con,
390 int x, int y, int width,
391 struct border_colors *colors, struct wlr_texture *title_texture,
392 struct wlr_texture *marks_texture) {
393 struct wlr_box box;
394 float color[4];
395 struct sway_view *view = con->type == C_VIEW ? con->sway_view : NULL;
396 float output_scale = output->wlr_output->scale;
397 enum sway_container_layout layout = con->parent->layout;
398 bool is_last_child =
399 con->parent->children->items[con->parent->children->length - 1] == con;
382 400
383 // Single pixel bar above title 401 // Single pixel bar above title
384 memcpy(&color, colors->border, sizeof(float) * 4); 402 memcpy(&color, colors->border, sizeof(float) * 4);
385 premultiply_alpha(color, con->alpha); 403 premultiply_alpha(color, con->alpha);
386 box.x = con->x; 404 box.x = x;
387 box.y = con->y; 405 box.y = y;
388 box.width = con->width; 406 box.width = width;
389 box.height = 1; 407 box.height = TITLEBAR_BORDER_THICKNESS;
390 scale_box(&box, output_scale); 408 scale_box(&box, output_scale);
391 render_rect(output->wlr_output, output_damage, &box, color); 409 render_rect(output->wlr_output, output_damage, &box, color);
392 410
393 // Setting these makes marks and title easier
394 size_t inner_x = con->x + view->border_thickness * view->border_left;
395 size_t inner_width = con->width - view->border_thickness * view->border_left
396 - view->border_thickness * view->border_right;
397
398 // Single pixel bar below title 411 // Single pixel bar below title
399 memcpy(&color, colors->border, sizeof(float) * 4); 412 size_t left_offset = 0, right_offset = 0;
400 premultiply_alpha(color, con->alpha); 413 bool connects_sides = false;
401 box.x = inner_x; 414 if (layout == L_HORIZ || layout == L_VERT ||
402 box.y = view->y - 1; 415 (layout == L_STACKED && is_last_child)) {
403 box.width = inner_width; 416 if (view) {
404 box.height = 1; 417 left_offset = view->border_left * view->border_thickness;
418 right_offset = view->border_right * view->border_thickness;
419 connects_sides = true;
420 }
421 }
422 box.x = x + left_offset;
423 box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
424 box.width = width - left_offset - right_offset;
425 box.height = TITLEBAR_BORDER_THICKNESS;
405 scale_box(&box, output_scale); 426 scale_box(&box, output_scale);
406 render_rect(output->wlr_output, output_damage, &box, color); 427 render_rect(output->wlr_output, output_damage, &box, color);
407 428
429 if (layout == L_TABBED) {
430 // Single pixel left edge
431 box.x = x;
432 box.y = y + TITLEBAR_BORDER_THICKNESS;
433 box.width = TITLEBAR_BORDER_THICKNESS;
434 box.height =
435 container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2;
436 scale_box(&box, output_scale);
437 render_rect(output->wlr_output, output_damage, &box, color);
438
439 // Single pixel right edge
440 box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale;
441 render_rect(output->wlr_output, output_damage, &box, color);
442 }
443
444 size_t inner_width = width - TITLEBAR_H_PADDING * 2;
445
408 // Marks 446 // Marks
409 size_t marks_width = 0; 447 size_t marks_width = 0;
410 if (config->show_marks && marks_texture) { 448 if (config->show_marks && marks_texture) {
411 struct wlr_box texture_box; 449 struct wlr_box texture_box;
412 wlr_texture_get_size(marks_texture, 450 wlr_texture_get_size(marks_texture,
413 &texture_box.width, &texture_box.height); 451 &texture_box.width, &texture_box.height);
414 texture_box.x = (inner_x + inner_width) * output_scale - texture_box.width; 452 texture_box.x =
415 texture_box.y = (con->y + view->border_thickness) * output_scale; 453 (x + width - TITLEBAR_H_PADDING) * output_scale - texture_box.width;
454 texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale;
416 455
417 float matrix[9]; 456 float matrix[9];
418 wlr_matrix_project_box(matrix, &texture_box, 457 wlr_matrix_project_box(matrix, &texture_box,
419 WL_OUTPUT_TRANSFORM_NORMAL, 458 WL_OUTPUT_TRANSFORM_NORMAL,
420 0.0, output->wlr_output->transform_matrix); 459 0.0, output->wlr_output->transform_matrix);
421 460
461 if (inner_width * output_scale < texture_box.width) {
462 texture_box.width = inner_width * output_scale;
463 }
422 render_texture(output->wlr_output, output_damage, marks_texture, 464 render_texture(output->wlr_output, output_damage, marks_texture,
423 &texture_box, matrix, con->alpha); 465 &texture_box, matrix, con->alpha);
424 marks_width = texture_box.width; 466 marks_width = texture_box.width;
@@ -430,8 +472,8 @@ static void render_container_simple_border_normal(struct sway_output *output,
430 struct wlr_box texture_box; 472 struct wlr_box texture_box;
431 wlr_texture_get_size(title_texture, 473 wlr_texture_get_size(title_texture,
432 &texture_box.width, &texture_box.height); 474 &texture_box.width, &texture_box.height);
433 texture_box.x = inner_x * output_scale; 475 texture_box.x = (x + TITLEBAR_H_PADDING) * output_scale;
434 texture_box.y = (con->y + view->border_thickness) * output_scale; 476 texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale;
435 477
436 float matrix[9]; 478 float matrix[9];
437 wlr_matrix_project_box(matrix, &texture_box, 479 wlr_matrix_project_box(matrix, &texture_box,
@@ -446,104 +488,89 @@ static void render_container_simple_border_normal(struct sway_output *output,
446 title_width = texture_box.width; 488 title_width = texture_box.width;
447 } 489 }
448 490
449 // Title background - above the text 491 // Padding above title
450 memcpy(&color, colors->background, sizeof(float) * 4); 492 memcpy(&color, colors->background, sizeof(float) * 4);
451 premultiply_alpha(color, con->alpha); 493 premultiply_alpha(color, con->alpha);
452 box.x = inner_x; 494 box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
453 box.y = con->y + 1; 495 box.y = y + TITLEBAR_BORDER_THICKNESS;
454 box.width = inner_width; 496 box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2;
455 box.height = view->border_thickness - 1; 497 box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS;
456 scale_box(&box, output_scale); 498 scale_box(&box, output_scale);
457 render_rect(output->wlr_output, output_damage, &box, color); 499 render_rect(output->wlr_output, output_damage, &box, color);
458 500
459 // Title background - below the text 501 // Padding below title
460 box.y = (con->y + view->border_thickness + config->font_height) 502 box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale;
461 * output_scale;
462 render_rect(output->wlr_output, output_damage, &box, color); 503 render_rect(output->wlr_output, output_damage, &box, color);
463 504
464 // Title background - filler between title and marks 505 // Filler between title and marks
465 box.width = inner_width * output_scale - title_width - marks_width; 506 box.width = inner_width * output_scale - title_width - marks_width;
466 if (box.width > 0) { 507 if (box.width > 0) {
467 box.x = inner_x * output_scale + title_width; 508 box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_width;
468 box.y = (con->y + view->border_thickness) * output_scale; 509 box.y = (y + TITLEBAR_V_PADDING) * output_scale;
469 box.height = config->font_height * output_scale; 510 box.height = config->font_height * output_scale;
470 render_rect(output->wlr_output, output_damage, &box, color); 511 render_rect(output->wlr_output, output_damage, &box, color);
471 } 512 }
472}
473 513
474/** 514 // Padding left of title
475 * Render decorations for a view with "border pixel". 515 left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
476 * 516 box.x = x + left_offset;
477 * Care must be taken not to render over the same pixel multiple times, 517 box.y = y + TITLEBAR_V_PADDING;
478 * otherwise the colors will be incorrect when using opacity. 518 box.width = TITLEBAR_H_PADDING - left_offset;
479 */ 519 box.height = config->font_height;
480static void render_container_simple_border_pixel(struct sway_output *output, 520 scale_box(&box, output_scale);
481 pixman_region32_t *output_damage, struct sway_container *con, 521 render_rect(output->wlr_output, output_damage, &box, color);
482 struct border_colors *colors) {
483 struct wlr_box box;
484 float color[4];
485 struct sway_view *view = con->sway_view;
486 float output_scale = output->wlr_output->scale;
487 522
488 if (view->border_left) { 523 // Padding right of marks
489 // Child border - left edge 524 right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
490 memcpy(&color, colors->child_border, sizeof(float) * 4); 525 box.x = x + width - TITLEBAR_H_PADDING;
491 premultiply_alpha(color, con->alpha); 526 box.y = y + TITLEBAR_V_PADDING;
492 box.x = con->x; 527 box.width = TITLEBAR_H_PADDING - right_offset;
493 box.y = con->y + view->border_thickness * view->border_top; 528 box.height = config->font_height;
494 box.width = view->border_thickness; 529 scale_box(&box, output_scale);
495 box.height = con->height - view->border_thickness 530 render_rect(output->wlr_output, output_damage, &box, color);
496 * (view->border_top + view->border_bottom);
497 scale_box(&box, output_scale);
498 render_rect(output->wlr_output, output_damage, &box, color);
499 }
500 531
501 if (view->border_right) { 532 if (connects_sides) {
502 // Child border - right edge 533 // Left pixel in line with bottom bar
503 if (con->parent->children->length == 1 534 box.x = x;
504 && con->parent->layout == L_HORIZ) { 535 box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
505 memcpy(&color, colors->indicator, sizeof(float) * 4); 536 box.width = view->border_thickness * view->border_left;
506 } else { 537 box.height = TITLEBAR_BORDER_THICKNESS;
507 memcpy(&color, colors->child_border, sizeof(float) * 4);
508 }
509 premultiply_alpha(color, con->alpha);
510 box.x = con->x + con->width - view->border_thickness;
511 box.y = con->y + view->border_thickness * view->border_top;
512 box.width = view->border_thickness;
513 box.height = con->height - view->border_thickness
514 * (view->border_top + view->border_bottom);
515 scale_box(&box, output_scale); 538 scale_box(&box, output_scale);
516 render_rect(output->wlr_output, output_damage, &box, color); 539 render_rect(output->wlr_output, output_damage, &box, color);
517 }
518 540
519 if (view->border_top) { 541 // Right pixel in line with bottom bar
520 // Child border - top edge 542 box.x = x + width - view->border_thickness * view->border_right;
521 memcpy(&color, colors->child_border, sizeof(float) * 4); 543 box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
522 premultiply_alpha(color, con->alpha); 544 box.width = view->border_thickness * view->border_right;
523 box.x = con->x; 545 box.height = TITLEBAR_BORDER_THICKNESS;
524 box.y = con->y;
525 box.width = con->width;
526 box.height = view->border_thickness;
527 scale_box(&box, output_scale); 546 scale_box(&box, output_scale);
528 render_rect(output->wlr_output, output_damage, &box, color); 547 render_rect(output->wlr_output, output_damage, &box, color);
529 } 548 }
549}
530 550
531 if (view->border_bottom) { 551/**
532 // Child border - bottom edge 552 * Render the top border line for a view using "border pixel".
533 if (con->parent->children->length == 1 553 */
534 && con->parent->layout == L_VERT) { 554static void render_top_border(struct sway_output *output,
535 memcpy(&color, colors->indicator, sizeof(float) * 4); 555 pixman_region32_t *output_damage, struct sway_container *con,
536 } else { 556 struct border_colors *colors) {
537 memcpy(&color, colors->child_border, sizeof(float) * 4); 557 struct sway_view *view = con->sway_view;
538 } 558 if (!view->border_top) {
539 premultiply_alpha(color, con->alpha); 559 return;
540 box.x = con->x;
541 box.y = con->y + con->height - view->border_thickness;
542 box.width = con->width;
543 box.height = view->border_thickness;
544 scale_box(&box, output_scale);
545 render_rect(output->wlr_output, output_damage, &box, color);
546 } 560 }
561 struct wlr_box box;
562 float color[4];
563 float output_scale = output->wlr_output->scale;
564
565 // Child border - top edge
566 memcpy(&color, colors->child_border, sizeof(float) * 4);
567 premultiply_alpha(color, con->alpha);
568 box.x = con->x;
569 box.y = con->y;
570 box.width = con->width;
571 box.height = view->border_thickness;
572 scale_box(&box, output_scale);
573 render_rect(output->wlr_output, output_damage, &box, color);
547} 574}
548 575
549static void render_container(struct sway_output *output, 576static void render_container(struct sway_output *output,
@@ -565,33 +592,30 @@ static void render_container_simple(struct sway_output *output,
565 struct sway_container *child = con->children->items[i]; 592 struct sway_container *child = con->children->items[i];
566 593
567 if (child->type == C_VIEW) { 594 if (child->type == C_VIEW) {
568 if (child->sway_view->border != B_NONE) { 595 struct border_colors *colors;
569 struct border_colors *colors; 596 struct wlr_texture *title_texture;
570 struct wlr_texture *title_texture; 597 struct wlr_texture *marks_texture;
571 struct wlr_texture *marks_texture; 598 if (focus == child || parent_focused) {
572 if (focus == child || parent_focused) { 599 colors = &config->border_colors.focused;
573 colors = &config->border_colors.focused; 600 title_texture = child->title_focused;
574 title_texture = child->title_focused; 601 marks_texture = child->sway_view->marks_focused;
575 marks_texture = child->sway_view->marks_focused; 602 } else if (seat_get_focus_inactive(seat, con) == child) {
576 } else if (seat_get_focus_inactive(seat, con) == child) { 603 colors = &config->border_colors.focused_inactive;
577 colors = &config->border_colors.focused_inactive; 604 title_texture = child->title_focused_inactive;
578 title_texture = child->title_focused_inactive; 605 marks_texture = child->sway_view->marks_focused_inactive;
579 marks_texture = child->sway_view->marks_focused_inactive; 606 } else {
580 } else { 607 colors = &config->border_colors.unfocused;
581 colors = &config->border_colors.unfocused; 608 title_texture = child->title_unfocused;
582 title_texture = child->title_unfocused; 609 marks_texture = child->sway_view->marks_unfocused;
583 marks_texture = child->sway_view->marks_unfocused; 610 }
584 } 611
585 612 if (child->sway_view->border == B_NORMAL) {
586 if (child->sway_view->border == B_NORMAL) { 613 render_titlebar(output, damage, child, child->x, child->y,
587 render_container_simple_border_normal(output, damage, 614 child->width, colors, title_texture, marks_texture);
588 child, colors, title_texture, marks_texture); 615 } else {
589 } else { 616 render_top_border(output, damage, child, colors);
590 render_container_simple_border_pixel(output, damage, child,
591 colors);
592 }
593 } 617 }
594 render_view(child->sway_view, output, damage); 618 render_view(output, damage, child, colors);
595 } else { 619 } else {
596 render_container(output, damage, child, 620 render_container(output, damage, child,
597 parent_focused || focus == child); 621 parent_focused || focus == child);
@@ -599,154 +623,71 @@ static void render_container_simple(struct sway_output *output,
599 } 623 }
600} 624}
601 625
602static void render_tab(struct sway_output *output, pixman_region32_t *damage, 626/**
603 struct sway_container *parent, int child_index, 627 * Render a container's children using the L_TABBED layout.
604 struct border_colors *colors, struct wlr_texture *title_texture) { 628 */
605 struct sway_container *con = parent->children->items[child_index]; 629static void render_container_tabbed(struct sway_output *output,
606 float output_scale = output->wlr_output->scale; 630 pixman_region32_t *damage, struct sway_container *con,
607 float color[4]; 631 bool parent_focused) {
608 struct wlr_box box; 632 if (!con->children->length) {
609 633 return;
610 int tab_width = parent->width / parent->children->length;
611 int x = parent->x + tab_width * child_index;
612 // Make last tab use the remaining width of the parent
613 if (child_index == parent->children->length - 1) {
614 tab_width = parent->width - tab_width * child_index;
615 } 634 }
635 struct sway_seat *seat = input_manager_current_seat(input_manager);
636 struct sway_container *focus = seat_get_focus(seat);
637 struct sway_container *current = seat_get_active_child(seat, con);
638 struct border_colors *current_colors = NULL;
616 639
617 // Single pixel bar above title 640 // Render tabs
618 memcpy(&color, colors->border, sizeof(float) * 4); 641 for (int i = 0; i < con->children->length; ++i) {
619 premultiply_alpha(color, con->alpha); 642 struct sway_container *child = con->children->items[i];
620 box.x = x; 643 struct border_colors *colors;
621 box.y = parent->y; 644 struct wlr_texture *title_texture;
622 box.width = tab_width; 645 struct wlr_texture *marks_texture;
623 box.height = 1; 646 struct sway_view *view =
624 scale_box(&box, output_scale); 647 child->type == C_VIEW ? child->sway_view : NULL;
625 render_rect(output->wlr_output, damage, &box, color);
626
627 // Single pixel bar below title
628 box.y = (parent->y + config->border_thickness * 2 + config->font_height - 1)
629 * output_scale;
630 render_rect(output->wlr_output, damage, &box, color);
631
632 // Single pixel bar on left
633 box.x = x;
634 box.y = parent->y + 1;
635 box.width = 1;
636 box.height = config->border_thickness * 2 + config->font_height - 2;
637 scale_box(&box, output_scale);
638 render_rect(output->wlr_output, damage, &box, color);
639
640 // Single pixel bar on right
641 box.x = (x + tab_width - 1) * output_scale;
642 render_rect(output->wlr_output, damage, &box, color);
643
644 // Title text
645 size_t title_width = 0;
646 if (title_texture) {
647 struct wlr_box texture_box;
648 wlr_texture_get_size(title_texture,
649 &texture_box.width, &texture_box.height);
650 texture_box.x = (x + 1 + config->border_thickness) * output_scale;
651 texture_box.y = (parent->y + config->border_thickness) * output_scale;
652
653 float matrix[9];
654 wlr_matrix_project_box(matrix, &texture_box,
655 WL_OUTPUT_TRANSFORM_NORMAL,
656 0.0, output->wlr_output->transform_matrix);
657 648
658 int available = (tab_width - config->border_thickness * 2 - 2) 649 if (focus == child || parent_focused) {
659 * output_scale; 650 colors = &config->border_colors.focused;
660 if (texture_box.width > available) { 651 title_texture = child->title_focused;
661 texture_box.width = available; 652 marks_texture = view ? view->marks_focused : NULL;
653 } else if (child == current) {
654 colors = &config->border_colors.focused_inactive;
655 title_texture = child->title_focused_inactive;
656 marks_texture = view ? view->marks_focused : NULL;
657 } else {
658 colors = &config->border_colors.unfocused;
659 title_texture = child->title_unfocused;
660 marks_texture = view ? view->marks_unfocused : NULL;
662 } 661 }
663 render_texture(output->wlr_output, damage, title_texture,
664 &texture_box, matrix, 1.0);
665 title_width = texture_box.width;
666 }
667
668 // Title background - above the text
669 memcpy(&color, colors->background, sizeof(float) * 4);
670 premultiply_alpha(color, con->alpha);
671 box.x = x + 1;
672 box.y = parent->y + 1;
673 box.width = tab_width - 2;
674 box.height = config->border_thickness - 1;
675 scale_box(&box, output_scale);
676 render_rect(output->wlr_output, damage, &box, color);
677 662
678 // Title background - below the text 663 int tab_width = con->width / con->children->length;
679 box.y = (parent->y + config->border_thickness + config->font_height) 664 int x = con->x + tab_width * i;
680 * output_scale; 665 // Make last tab use the remaining width of the parent
681 render_rect(output->wlr_output, damage, &box, color); 666 if (i == con->children->length - 1) {
682 667 tab_width = con->width - tab_width * i;
683 // Title background - left of text
684 box.x = x + 1;
685 box.y = parent->y + config->border_thickness;
686 box.width = config->border_thickness;
687 box.height = config->font_height;
688 scale_box(&box, output_scale);
689 render_rect(output->wlr_output, damage, &box, color);
690
691 // Title background - right of text
692 box.x = (x + 1 + config->border_thickness) * output_scale + title_width;
693 box.y = (parent->y + config->border_thickness) * output_scale;
694 box.width = (tab_width - config->border_thickness - 2) * output_scale
695 - title_width;
696 box.height = config->font_height * output_scale;
697 render_rect(output->wlr_output, damage, &box, color);
698}
699
700static void render_tab_content(struct sway_output *output,
701 pixman_region32_t *damage, struct sway_container *con,
702 struct border_colors *colors) {
703 struct sway_view *view = con->sway_view;
704 render_view(view, output, damage);
705
706 struct wlr_box box;
707 float output_scale = output->wlr_output->scale;
708 float color[4];
709
710 if (view->border != B_NONE) {
711 if (view->border_left) {
712 memcpy(&color, colors->child_border, sizeof(float) * 4);
713 premultiply_alpha(color, con->alpha);
714 box.x = con->x;
715 box.y = con->y + config->border_thickness * 2 + config->font_height;
716 box.width = view->border_thickness;
717 box.height = view->height;
718 scale_box(&box, output_scale);
719 render_rect(output->wlr_output, damage, &box, color);
720 } 668 }
721 669
722 if (view->border_right) { 670 render_titlebar(output, damage, child, x, child->y, tab_width, colors,
723 memcpy(&color, colors->child_border, sizeof(float) * 4); 671 title_texture, marks_texture);
724 premultiply_alpha(color, con->alpha);
725 box.x = view->x + view->width;
726 box.y = con->y + config->border_thickness * 2 + config->font_height;
727 box.width = view->border_thickness;
728 box.height = view->height;
729 scale_box(&box, output_scale);
730 render_rect(output->wlr_output, damage, &box, color);
731 }
732 672
733 if (view->border_bottom) { 673 if (child == current) {
734 memcpy(&color, colors->child_border, sizeof(float) * 4); 674 current_colors = colors;
735 premultiply_alpha(color, con->alpha);
736 box.x = con->x;
737 box.y = view->y + view->height;
738 box.width = con->width;
739 box.height = view->border_thickness;
740 scale_box(&box, output_scale);
741 render_rect(output->wlr_output, damage, &box, color);
742 } 675 }
743 } 676 }
677
678 // Render surface and left/right/bottom borders
679 if (current->type == C_VIEW) {
680 render_view(output, damage, current, current_colors);
681 } else {
682 render_container(output, damage, current,
683 parent_focused || current == focus);
684 }
744} 685}
745 686
746/** 687/**
747 * Render a container's children using the L_TABBED layout. 688 * Render a container's children using the L_STACKED layout.
748 */ 689 */
749static void render_container_tabbed(struct sway_output *output, 690static void render_container_stacked(struct sway_output *output,
750 pixman_region32_t *damage, struct sway_container *con, 691 pixman_region32_t *damage, struct sway_container *con,
751 bool parent_focused) { 692 bool parent_focused) {
752 if (!con->children->length) { 693 if (!con->children->length) {
@@ -757,24 +698,32 @@ static void render_container_tabbed(struct sway_output *output,
757 struct sway_container *current = seat_get_active_child(seat, con); 698 struct sway_container *current = seat_get_active_child(seat, con);
758 struct border_colors *current_colors = NULL; 699 struct border_colors *current_colors = NULL;
759 700
760 // Render tabs 701 // Render titles
761 for (int i = 0; i < con->children->length; ++i) { 702 for (int i = 0; i < con->children->length; ++i) {
762 struct sway_container *child = con->children->items[i]; 703 struct sway_container *child = con->children->items[i];
763 struct border_colors *colors; 704 struct border_colors *colors;
764 struct wlr_texture *title_texture; 705 struct wlr_texture *title_texture;
706 struct wlr_texture *marks_texture;
707 struct sway_view *view =
708 child->type == C_VIEW ? child->sway_view : NULL;
765 709
766 if (focus == child || parent_focused) { 710 if (focus == child || parent_focused) {
767 colors = &config->border_colors.focused; 711 colors = &config->border_colors.focused;
768 title_texture = child->title_focused; 712 title_texture = child->title_focused;
713 marks_texture = view ? view->marks_focused : NULL;
769 } else if (child == current) { 714 } else if (child == current) {
770 colors = &config->border_colors.focused_inactive; 715 colors = &config->border_colors.focused_inactive;
771 title_texture = child->title_focused_inactive; 716 title_texture = child->title_focused_inactive;
717 marks_texture = view ? view->marks_focused_inactive : NULL;
772 } else { 718 } else {
773 colors = &config->border_colors.unfocused; 719 colors = &config->border_colors.unfocused;
774 title_texture = child->title_unfocused; 720 title_texture = child->title_unfocused;
721 marks_texture = view ? view->marks_unfocused : NULL;
775 } 722 }
776 723
777 render_tab(output, damage, con, i, colors, title_texture); 724 int y = con->y + container_titlebar_height() * i;
725 render_titlebar(output, damage, child, child->x, y, child->width,
726 colors, title_texture, marks_texture);
778 727
779 if (child == current) { 728 if (child == current) {
780 current_colors = colors; 729 current_colors = colors;
@@ -783,21 +732,13 @@ static void render_container_tabbed(struct sway_output *output,
783 732
784 // Render surface and left/right/bottom borders 733 // Render surface and left/right/bottom borders
785 if (current->type == C_VIEW) { 734 if (current->type == C_VIEW) {
786 render_tab_content(output, damage, current, current_colors); 735 render_view(output, damage, current, current_colors);
787 } else { 736 } else {
788 render_container(output, damage, current, 737 render_container(output, damage, current,
789 parent_focused || current == focus); 738 parent_focused || current == focus);
790 } 739 }
791} 740}
792 741
793/**
794 * Render a container's children using the L_STACKED layout.
795 */
796static void render_container_stacked(struct sway_output *output,
797 pixman_region32_t *damage, struct sway_container *con) {
798 // TODO
799}
800
801static void render_container(struct sway_output *output, 742static void render_container(struct sway_output *output,
802 pixman_region32_t *damage, struct sway_container *con, 743 pixman_region32_t *damage, struct sway_container *con,
803 bool parent_focused) { 744 bool parent_focused) {
@@ -808,7 +749,7 @@ static void render_container(struct sway_output *output,
808 render_container_simple(output, damage, con, parent_focused); 749 render_container_simple(output, damage, con, parent_focused);
809 break; 750 break;
810 case L_STACKED: 751 case L_STACKED:
811 render_container_stacked(output, damage, con); 752 render_container_stacked(output, damage, con, parent_focused);
812 break; 753 break;
813 case L_TABBED: 754 case L_TABBED:
814 render_container_tabbed(output, damage, con, parent_focused); 755 render_container_tabbed(output, damage, con, parent_focused);
@@ -868,7 +809,8 @@ static void render_output(struct sway_output *output, struct timespec *when,
868 } 809 }
869 810
870 // TODO: handle views smaller than the output 811 // TODO: handle views smaller than the output
871 render_view(workspace->sway_workspace->fullscreen, output, damage); 812 render_view_surfaces(
813 workspace->sway_workspace->fullscreen, output, damage);
872 814
873 if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) { 815 if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) {
874 render_unmanaged(output, damage, 816 render_unmanaged(output, damage,
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index e0b987d2..9a0b4f01 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -147,10 +147,10 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
147 struct sway_container *c = container_at_coords(cursor->seat, 147 struct sway_container *c = container_at_coords(cursor->seat,
148 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); 148 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
149 if (c && config->focus_follows_mouse && allow_refocusing) { 149 if (c && config->focus_follows_mouse && allow_refocusing) {
150 if (c->type == C_WORKSPACE) { 150 struct sway_container *focus = seat_get_focus(cursor->seat);
151 if (focus && c->type == C_WORKSPACE) {
151 // Only follow the mouse if it would move to a new output 152 // Only follow the mouse if it would move to a new output
152 // Otherwise we'll focus the workspace, which is probably wrong 153 // Otherwise we'll focus the workspace, which is probably wrong
153 struct sway_container *focus = seat_get_focus(cursor->seat);
154 if (focus->type != C_OUTPUT) { 154 if (focus->type != C_OUTPUT) {
155 focus = container_parent(focus, C_OUTPUT); 155 focus = container_parent(focus, C_OUTPUT);
156 } 156 }
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 8734e8f8..15ed6f80 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -22,6 +22,7 @@
22#include "sway/server.h" 22#include "sway/server.h"
23#include "sway/input/input-manager.h" 23#include "sway/input/input-manager.h"
24#include "sway/input/seat.h" 24#include "sway/input/seat.h"
25#include "sway/tree/view.h"
25#include "list.h" 26#include "list.h"
26#include "log.h" 27#include "log.h"
27 28
@@ -429,6 +430,16 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,
429 json_object_new_boolean(visible)); 430 json_object_new_boolean(visible));
430} 431}
431 432
433static void ipc_get_marks_callback(struct sway_container *con, void *data) {
434 json_object *marks = (json_object *)data;
435 if (con->type == C_VIEW && con->sway_view->marks) {
436 for (int i = 0; i < con->sway_view->marks->length; ++i) {
437 char *mark = (char *)con->sway_view->marks->items[i];
438 json_object_array_add(marks, json_object_new_string(mark));
439 }
440 }
441}
442
432void ipc_client_handle_command(struct ipc_client *client) { 443void ipc_client_handle_command(struct ipc_client *client) {
433 if (!sway_assert(client != NULL, "client != NULL")) { 444 if (!sway_assert(client != NULL, "client != NULL")) {
434 return; 445 return;
@@ -569,6 +580,17 @@ void ipc_client_handle_command(struct ipc_client *client) {
569 goto exit_cleanup; 580 goto exit_cleanup;
570 } 581 }
571 582
583 case IPC_GET_MARKS:
584 {
585 json_object *marks = json_object_new_array();
586 container_descendants(&root_container, C_VIEW, ipc_get_marks_callback,
587 marks);
588 const char *json_string = json_object_to_json_string(marks);
589 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
590 json_object_put(marks);
591 goto exit_cleanup;
592 }
593
572 case IPC_GET_VERSION: 594 case IPC_GET_VERSION:
573 { 595 {
574 json_object *version = ipc_json_get_version(); 596 json_object *version = ipc_json_get_version();
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 8aebc0cc..bdef56ea 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -86,12 +86,14 @@ static void apply_horiz_layout(struct sway_container *parent) {
86 if (!num_children) { 86 if (!num_children) {
87 return; 87 return;
88 } 88 }
89 size_t parent_height = parent->height;
90 size_t parent_offset = 0; 89 size_t parent_offset = 0;
91 if (parent->parent->layout == L_TABBED) { 90 if (parent->parent->layout == L_TABBED) {
92 parent_offset = config->border_thickness * 2 + config->font_height; 91 parent_offset = container_titlebar_height();
93 parent_height -= parent_offset; 92 } else if (parent->parent->layout == L_STACKED) {
93 parent_offset =
94 container_titlebar_height() * parent->parent->children->length;
94 } 95 }
96 size_t parent_height = parent->height - parent_offset;
95 97
96 // Calculate total width of children 98 // Calculate total width of children
97 double total_width = 0; 99 double total_width = 0;
@@ -132,12 +134,14 @@ static void apply_vert_layout(struct sway_container *parent) {
132 if (!num_children) { 134 if (!num_children) {
133 return; 135 return;
134 } 136 }
135 size_t parent_height = parent->height;
136 size_t parent_offset = 0; 137 size_t parent_offset = 0;
137 if (parent->parent->layout == L_TABBED) { 138 if (parent->parent->layout == L_TABBED) {
138 parent_offset = config->border_thickness * 2 + config->font_height; 139 parent_offset = container_titlebar_height();
139 parent_height -= parent_offset; 140 } else if (parent->parent->layout == L_STACKED) {
141 parent_offset =
142 container_titlebar_height() * parent->parent->children->length;
140 } 143 }
144 size_t parent_height = parent->height - parent_offset;
141 145
142 // Calculate total height of children 146 // Calculate total height of children
143 double total_height = 0; 147 double total_height = 0;
@@ -173,16 +177,24 @@ static void apply_vert_layout(struct sway_container *parent) {
173 child->height = parent->y + parent_offset + parent_height - child->y; 177 child->height = parent->y + parent_offset + parent_height - child->y;
174} 178}
175 179
176static void apply_tabbed_layout(struct sway_container *parent) { 180static void apply_tabbed_or_stacked_layout(struct sway_container *parent) {
177 if (!parent->children->length) { 181 if (!parent->children->length) {
178 return; 182 return;
179 } 183 }
184 size_t parent_offset = 0;
185 if (parent->parent->layout == L_TABBED) {
186 parent_offset = container_titlebar_height();
187 } else if (parent->parent->layout == L_STACKED) {
188 parent_offset =
189 container_titlebar_height() * parent->parent->children->length;
190 }
191 size_t parent_height = parent->height - parent_offset;
180 for (int i = 0; i < parent->children->length; ++i) { 192 for (int i = 0; i < parent->children->length; ++i) {
181 struct sway_container *child = parent->children->items[i]; 193 struct sway_container *child = parent->children->items[i];
182 child->x = parent->x; 194 child->x = parent->x;
183 child->y = parent->y; 195 child->y = parent->y + parent_offset;
184 child->width = parent->width; 196 child->width = parent->width;
185 child->height = parent->height; 197 child->height = parent_height;
186 } 198 }
187} 199}
188 200
@@ -217,7 +229,8 @@ void arrange_children_of(struct sway_container *parent) {
217 apply_vert_layout(parent); 229 apply_vert_layout(parent);
218 break; 230 break;
219 case L_TABBED: 231 case L_TABBED:
220 apply_tabbed_layout(parent); 232 case L_STACKED:
233 apply_tabbed_or_stacked_layout(parent);
221 break; 234 break;
222 default: 235 default:
223 wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout); 236 wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout);
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 5d88325f..f29a9adc 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -21,6 +21,7 @@
21#include "sway/tree/view.h" 21#include "sway/tree/view.h"
22#include "sway/tree/workspace.h" 22#include "sway/tree/workspace.h"
23#include "log.h" 23#include "log.h"
24#include "stringop.h"
24 25
25static list_t *bfs_queue; 26static list_t *bfs_queue;
26 27
@@ -510,7 +511,7 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent,
510 struct sway_seat *seat = input_manager_current_seat(input_manager); 511 struct sway_seat *seat = input_manager_current_seat(input_manager);
511 512
512 // Tab titles 513 // Tab titles
513 int title_height = config->border_thickness * 2 + config->font_height; 514 int title_height = container_titlebar_height();
514 if (oy < parent->y + title_height) { 515 if (oy < parent->y + title_height) {
515 int tab_width = parent->width / parent->children->length; 516 int tab_width = parent->width / parent->children->length;
516 int child_index = (ox - parent->x) / tab_width; 517 int child_index = (ox - parent->x) / tab_width;
@@ -533,8 +534,23 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent,
533static struct sway_container *container_at_stacked( 534static struct sway_container *container_at_stacked(
534 struct sway_container *parent, double ox, double oy, 535 struct sway_container *parent, double ox, double oy,
535 struct wlr_surface **surface, double *sx, double *sy) { 536 struct wlr_surface **surface, double *sx, double *sy) {
536 // TODO 537 if (oy < parent->y || oy > parent->y + parent->height) {
537 return NULL; 538 return NULL;
539 }
540 struct sway_seat *seat = input_manager_current_seat(input_manager);
541
542 // Title bars
543 int title_height = container_titlebar_height();
544 int child_index = (oy - parent->y) / title_height;
545 if (child_index < parent->children->length) {
546 struct sway_container *child = parent->children->items[child_index];
547 return seat_get_focus_inactive(seat, child);
548 }
549
550 // Surfaces
551 struct sway_container *current = seat_get_active_child(seat, parent);
552
553 return container_at(current, ox, oy, surface, sx, sy);
538} 554}
539 555
540/** 556/**
@@ -759,42 +775,36 @@ void container_calculate_title_height(struct sway_container *container) {
759} 775}
760 776
761/** 777/**
762 * Calculate and return the length of the concatenated child titles. 778 * Calculate and return the length of the tree representation.
763 * An example concatenated title is: V[Terminal, Firefox] 779 * An example tree representation is: V[Terminal, Firefox]
764 * If buffer is not NULL, also populate the buffer with the concatenated title. 780 * If buffer is not NULL, also populate the buffer with the representation.
765 */ 781 */
766static size_t concatenate_child_titles(struct sway_container *parent, 782static size_t get_tree_representation(struct sway_container *parent, char *buffer) {
767 char *buffer) { 783 size_t len = 2;
768 size_t len = 2; // V[ 784 switch (parent->layout) {
769 if (buffer) { 785 case L_VERT:
770 switch (parent->layout) { 786 lenient_strcat(buffer, "V[");
771 case L_VERT: 787 break;
772 strcpy(buffer, "V["); 788 case L_HORIZ:
773 break; 789 lenient_strcat(buffer, "H[");
774 case L_HORIZ: 790 break;
775 strcpy(buffer, "H["); 791 case L_TABBED:
776 break; 792 lenient_strcat(buffer, "T[");
777 case L_TABBED: 793 break;
778 strcpy(buffer, "T["); 794 case L_STACKED:
779 break; 795 lenient_strcat(buffer, "S[");
780 case L_STACKED: 796 break;
781 strcpy(buffer, "S["); 797 case L_FLOATING:
782 break; 798 lenient_strcat(buffer, "F[");
783 case L_FLOATING: 799 break;
784 strcpy(buffer, "F["); 800 case L_NONE:
785 break; 801 lenient_strcat(buffer, "D[");
786 case L_NONE: 802 break;
787 strcpy(buffer, "D[");
788 break;
789 }
790 } 803 }
791
792 for (int i = 0; i < parent->children->length; ++i) { 804 for (int i = 0; i < parent->children->length; ++i) {
793 if (i != 0) { 805 if (i != 0) {
794 len += 1; 806 ++len;
795 if (buffer) { 807 lenient_strcat(buffer, " ");
796 strcat(buffer, " ");
797 }
798 } 808 }
799 struct sway_container *child = parent->children->items[i]; 809 struct sway_container *child = parent->children->items[i];
800 const char *identifier = NULL; 810 const char *identifier = NULL;
@@ -804,46 +814,41 @@ static size_t concatenate_child_titles(struct sway_container *parent,
804 identifier = view_get_app_id(child->sway_view); 814 identifier = view_get_app_id(child->sway_view);
805 } 815 }
806 } else { 816 } else {
807 identifier = child->name; 817 identifier = child->formatted_title;
808 } 818 }
809 if (identifier) { 819 if (identifier) {
810 len += strlen(identifier); 820 len += strlen(identifier);
811 if (buffer) { 821 lenient_strcat(buffer, identifier);
812 strcat(buffer, identifier);
813 }
814 } else { 822 } else {
815 len += 6; 823 len += 6;
816 if (buffer) { 824 lenient_strcat(buffer, "(null)");
817 strcat(buffer, "(null)");
818 }
819 } 825 }
820 } 826 }
821 827 ++len;
822 len += 1; 828 lenient_strcat(buffer, "]");
823 if (buffer) {
824 strcat(buffer, "]");
825 }
826 return len; 829 return len;
827} 830}
828 831
829void container_notify_child_title_changed(struct sway_container *container) { 832void container_notify_subtree_changed(struct sway_container *container) {
830 if (!container || container->type != C_CONTAINER) { 833 if (!container || container->type != C_CONTAINER) {
831 return; 834 return;
832 } 835 }
833 if (container->formatted_title) { 836 free(container->formatted_title);
834 free(container->formatted_title); 837 container->formatted_title = NULL;
835 }
836 838
837 size_t len = concatenate_child_titles(container, NULL); 839 size_t len = get_tree_representation(container, NULL);
838 char *buffer = calloc(len + 1, sizeof(char)); 840 char *buffer = calloc(len + 1, sizeof(char));
839 if (!sway_assert(buffer, "Unable to allocate title string")) { 841 if (!sway_assert(buffer, "Unable to allocate title string")) {
840 return; 842 return;
841 } 843 }
842 concatenate_child_titles(container, buffer); 844 get_tree_representation(container, buffer);
843 845
844 container->name = buffer;
845 container->formatted_title = buffer; 846 container->formatted_title = buffer;
846 container_calculate_title_height(container); 847 container_calculate_title_height(container);
847 container_update_title_textures(container); 848 container_update_title_textures(container);
848 container_notify_child_title_changed(container->parent); 849 container_notify_subtree_changed(container->parent);
850}
851
852size_t container_titlebar_height() {
853 return config->font_height + TITLEBAR_V_PADDING * 2;
849} 854}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index f8acdf6c..21cec529 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -149,7 +149,7 @@ struct sway_container *container_remove_child(struct sway_container *child) {
149 } 149 }
150 } 150 }
151 child->parent = NULL; 151 child->parent = NULL;
152 container_notify_child_title_changed(parent); 152 container_notify_subtree_changed(parent);
153 153
154 return parent; 154 return parent;
155} 155}
@@ -184,12 +184,20 @@ void container_move_to(struct sway_container *container,
184 container_sort_workspaces(new_parent); 184 container_sort_workspaces(new_parent);
185 seat_set_focus(seat, new_parent); 185 seat_set_focus(seat, new_parent);
186 } 186 }
187 container_notify_child_title_changed(old_parent); 187 container_notify_subtree_changed(old_parent);
188 container_notify_child_title_changed(new_parent); 188 container_notify_subtree_changed(new_parent);
189 if (old_parent) { 189 if (old_parent) {
190 arrange_children_of(old_parent); 190 if (old_parent->type == C_OUTPUT) {
191 arrange_output(old_parent);
192 } else {
193 arrange_children_of(old_parent);
194 }
195 }
196 if (new_parent->type == C_OUTPUT) {
197 arrange_output(new_parent);
198 } else {
199 arrange_children_of(new_parent);
191 } 200 }
192 arrange_children_of(new_parent);
193 // If view was moved to a fullscreen workspace, refocus the fullscreen view 201 // If view was moved to a fullscreen workspace, refocus the fullscreen view
194 struct sway_container *new_workspace = container; 202 struct sway_container *new_workspace = container;
195 if (new_workspace->type != C_WORKSPACE) { 203 if (new_workspace->type != C_WORKSPACE) {
@@ -319,9 +327,11 @@ void container_move(struct sway_container *container,
319 current = container_parent(container, C_OUTPUT); 327 current = container_parent(container, C_OUTPUT);
320 } 328 }
321 329
322 if (parent != container_flatten(parent)) { 330 struct sway_container *new_parent = container_flatten(parent);
331 if (new_parent != parent) {
323 // Special case: we were the last one in this container, so flatten it 332 // Special case: we were the last one in this container, so flatten it
324 // and leave 333 // and leave
334 arrange_children_of(new_parent);
325 update_debug_tree(); 335 update_debug_tree();
326 return; 336 return;
327 } 337 }
@@ -489,8 +499,8 @@ void container_move(struct sway_container *container,
489 } 499 }
490 } 500 }
491 501
492 container_notify_child_title_changed(old_parent); 502 container_notify_subtree_changed(old_parent);
493 container_notify_child_title_changed(container->parent); 503 container_notify_subtree_changed(container->parent);
494 504
495 if (old_parent) { 505 if (old_parent) {
496 seat_set_focus(config->handler_context.seat, old_parent); 506 seat_set_focus(config->handler_context.seat, old_parent);
@@ -578,11 +588,19 @@ static struct sway_container *get_swayc_in_output_direction(
578 if (ws->children->length > 0) { 588 if (ws->children->length > 0) {
579 switch (dir) { 589 switch (dir) {
580 case MOVE_LEFT: 590 case MOVE_LEFT:
581 // get most right child of new output 591 if (ws->layout == L_HORIZ || ws->layout == L_TABBED) {
582 return ws->children->items[ws->children->length-1]; 592 // get most right child of new output
593 return ws->children->items[ws->children->length-1];
594 } else {
595 return seat_get_focus_inactive(seat, ws);
596 }
583 case MOVE_RIGHT: 597 case MOVE_RIGHT:
584 // get most left child of new output 598 if (ws->layout == L_HORIZ || ws->layout == L_TABBED) {
585 return ws->children->items[0]; 599 // get most left child of new output
600 return ws->children->items[0];
601 } else {
602 return seat_get_focus_inactive(seat, ws);
603 }
586 case MOVE_UP: 604 case MOVE_UP:
587 case MOVE_DOWN: { 605 case MOVE_DOWN: {
588 struct sway_container *focused = 606 struct sway_container *focused =
@@ -839,7 +857,7 @@ struct sway_container *container_split(struct sway_container *child,
839 container_add_child(cont, child); 857 container_add_child(cont, child);
840 } 858 }
841 859
842 container_notify_child_title_changed(cont); 860 container_notify_subtree_changed(cont);
843 861
844 return cont; 862 return cont;
845} 863}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 64597c02..812d7740 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -17,6 +17,7 @@
17#include "sway/tree/workspace.h" 17#include "sway/tree/workspace.h"
18#include "sway/config.h" 18#include "sway/config.h"
19#include "pango.h" 19#include "pango.h"
20#include "stringop.h"
20 21
21void view_init(struct sway_view *view, enum sway_view_type type, 22void view_init(struct sway_view *view, enum sway_view_type type,
22 const struct sway_view_impl *impl) { 23 const struct sway_view_impl *impl) {
@@ -141,9 +142,18 @@ void view_autoconfigure(struct sway_view *view) {
141 142
142 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); 143 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
143 144
144 int other_views = 1; 145 int other_views = 0;
145 if (config->hide_edge_borders == E_SMART) { 146 if (config->hide_edge_borders == E_SMART) {
146 other_views = container_count_descendants_of_type(ws, C_VIEW) - 1; 147 struct sway_container *con = view->swayc;
148 while (con != output) {
149 if (con->layout != L_TABBED && con->layout != L_STACKED) {
150 other_views += con->children ? con->children->length - 1 : 0;
151 if (other_views > 0) {
152 break;
153 }
154 }
155 con = con->parent;
156 }
147 } 157 }
148 158
149 view->border_top = view->border_bottom = true; 159 view->border_top = view->border_bottom = true;
@@ -173,11 +183,11 @@ void view_autoconfigure(struct sway_view *view) {
173 // area. We have to offset the surface y by the height of the title bar, and 183 // area. We have to offset the surface y by the height of the title bar, and
174 // disable any top border because we'll always have the title bar. 184 // disable any top border because we'll always have the title bar.
175 if (view->swayc->parent->layout == L_TABBED) { 185 if (view->swayc->parent->layout == L_TABBED) {
176 y_offset = config->border_thickness * 2 + config->font_height; 186 y_offset = container_titlebar_height();
177 view->border_top = 0; 187 view->border_top = 0;
178 } else if (view->swayc->parent->layout == L_STACKED) { 188 } else if (view->swayc->parent->layout == L_STACKED) {
179 y_offset = config->border_thickness * 2 + config->font_height; 189 y_offset = container_titlebar_height()
180 y_offset *= view->swayc->parent->children->length; 190 * view->swayc->parent->children->length;
181 view->border_top = 0; 191 view->border_top = 0;
182 } 192 }
183 193
@@ -199,7 +209,7 @@ void view_autoconfigure(struct sway_view *view) {
199 - view->border_thickness * view->border_bottom; 209 - view->border_thickness * view->border_bottom;
200 break; 210 break;
201 case B_NORMAL: 211 case B_NORMAL:
202 // Height is: border + title height + border + view height + border 212 // Height is: 1px border + 3px pad + title height + 3px pad + 1px border
203 x = view->swayc->x + view->border_thickness * view->border_left; 213 x = view->swayc->x + view->border_thickness * view->border_left;
204 width = view->swayc->width 214 width = view->swayc->width
205 - view->border_thickness * view->border_left 215 - view->border_thickness * view->border_left
@@ -209,10 +219,9 @@ void view_autoconfigure(struct sway_view *view) {
209 height = view->swayc->height - y_offset 219 height = view->swayc->height - y_offset
210 - view->border_thickness * view->border_bottom; 220 - view->border_thickness * view->border_bottom;
211 } else { 221 } else {
212 y = view->swayc->y + config->font_height + view->border_thickness * 2 222 y = view->swayc->y + container_titlebar_height();
213 + y_offset; 223 height = view->swayc->height - container_titlebar_height()
214 height = view->swayc->height - config->font_height 224 - view->border_thickness * view->border_bottom;
215 - view->border_thickness * (2 + view->border_bottom);
216 } 225 }
217 break; 226 break;
218 } 227 }
@@ -430,10 +439,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
430 // Check if there's any `assign` criteria for the view 439 // Check if there's any `assign` criteria for the view
431 list_t *criterias = criteria_for_view(view, 440 list_t *criterias = criteria_for_view(view,
432 CT_ASSIGN_WORKSPACE | CT_ASSIGN_OUTPUT); 441 CT_ASSIGN_WORKSPACE | CT_ASSIGN_OUTPUT);
442 struct sway_container *workspace = NULL;
433 if (criterias->length) { 443 if (criterias->length) {
434 struct criteria *criteria = criterias->items[0]; 444 struct criteria *criteria = criterias->items[0];
435 if (criteria->type == CT_ASSIGN_WORKSPACE) { 445 if (criteria->type == CT_ASSIGN_WORKSPACE) {
436 struct sway_container *workspace = workspace_by_name(criteria->target); 446 workspace = workspace_by_name(criteria->target);
437 if (!workspace) { 447 if (!workspace) {
438 workspace = workspace_create(NULL, criteria->target); 448 workspace = workspace_create(NULL, criteria->target);
439 } 449 }
@@ -460,9 +470,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
460 470
461 arrange_children_of(cont->parent); 471 arrange_children_of(cont->parent);
462 input_manager_set_focus(input_manager, cont); 472 input_manager_set_focus(input_manager, cont);
473 if (workspace) {
474 workspace_switch(workspace);
475 }
463 476
464 view_update_title(view, false); 477 view_update_title(view, false);
465 container_notify_child_title_changed(view->swayc->parent); 478 container_notify_subtree_changed(view->swayc->parent);
466 view_execute_criteria(view); 479 view_execute_criteria(view);
467 480
468 container_damage_whole(cont); 481 container_damage_whole(cont);
@@ -653,49 +666,35 @@ static size_t parse_title_format(struct sway_view *view, char *buffer) {
653 char *format = view->title_format; 666 char *format = view->title_format;
654 char *next = strchr(format, '%'); 667 char *next = strchr(format, '%');
655 while (next) { 668 while (next) {
656 if (buffer) { 669 // Copy everything up to the %
657 // Copy everything up to the % 670 lenient_strncat(buffer, format, next - format);
658 strncat(buffer, format, next - format);
659 }
660 len += next - format; 671 len += next - format;
661 format = next; 672 format = next;
662 673
663 if (strncmp(next, "%title", 6) == 0) { 674 if (strncmp(next, "%title", 6) == 0) {
664 if (buffer && title) { 675 lenient_strcat(buffer, title);
665 strcat(buffer, title);
666 }
667 len += title_len; 676 len += title_len;
668 format += 6; 677 format += 6;
669 } else if (strncmp(next, "%class", 6) == 0) { 678 } else if (strncmp(next, "%class", 6) == 0) {
670 if (buffer && class) { 679 lenient_strcat(buffer, class);
671 strcat(buffer, class);
672 }
673 len += class_len; 680 len += class_len;
674 format += 6; 681 format += 6;
675 } else if (strncmp(next, "%instance", 9) == 0) { 682 } else if (strncmp(next, "%instance", 9) == 0) {
676 if (buffer && instance) { 683 lenient_strcat(buffer, instance);
677 strcat(buffer, instance);
678 }
679 len += instance_len; 684 len += instance_len;
680 format += 9; 685 format += 9;
681 } else if (strncmp(next, "%shell", 6) == 0) { 686 } else if (strncmp(next, "%shell", 6) == 0) {
682 if (buffer) { 687 lenient_strcat(buffer, shell);
683 strcat(buffer, shell);
684 }
685 len += shell_len; 688 len += shell_len;
686 format += 6; 689 format += 6;
687 } else { 690 } else {
688 if (buffer) { 691 lenient_strcat(buffer, "%");
689 strcat(buffer, "%");
690 }
691 ++format; 692 ++format;
692 ++len; 693 ++len;
693 } 694 }
694 next = strchr(format, '%'); 695 next = strchr(format, '%');
695 } 696 }
696 if (buffer) { 697 lenient_strcat(buffer, format);
697 strcat(buffer, format);
698 }
699 len += strlen(format); 698 len += strlen(format);
700 699
701 return len; 700 return len;
@@ -751,7 +750,6 @@ void view_update_title(struct sway_view *view, bool force) {
751 } 750 }
752 container_calculate_title_height(view->swayc); 751 container_calculate_title_height(view->swayc);
753 container_update_title_textures(view->swayc); 752 container_update_title_textures(view->swayc);
754 container_notify_child_title_changed(view->swayc->parent);
755 config_update_font_height(false); 753 config_update_font_height(false);
756} 754}
757 755
diff --git a/swaylock/main.c b/swaylock/main.c
index 11b5e8c8..f89f2849 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -64,6 +64,52 @@ static void daemonize() {
64 } 64 }
65} 65}
66 66
67static void destroy_surface(struct swaylock_surface *surface) {
68 wl_list_remove(&surface->link);
69 if (surface->layer_surface != NULL) {
70 zwlr_layer_surface_v1_destroy(surface->layer_surface);
71 }
72 if (surface->surface != NULL) {
73 wl_surface_destroy(surface->surface);
74 }
75 destroy_buffer(&surface->buffers[0]);
76 destroy_buffer(&surface->buffers[1]);
77 wl_output_destroy(surface->output);
78 free(surface);
79}
80
81static const struct zwlr_layer_surface_v1_listener layer_surface_listener;
82
83static cairo_surface_t *select_image(struct swaylock_state *state,
84 struct swaylock_surface *surface);
85
86static void create_layer_surface(struct swaylock_surface *surface) {
87 struct swaylock_state *state = surface->state;
88
89 surface->image = select_image(state, surface);
90
91 surface->surface = wl_compositor_create_surface(state->compositor);
92 assert(surface->surface);
93
94 surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
95 state->layer_shell, surface->surface, surface->output,
96 ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen");
97 assert(surface->layer_surface);
98
99 zwlr_layer_surface_v1_set_size(surface->layer_surface, 0, 0);
100 zwlr_layer_surface_v1_set_anchor(surface->layer_surface,
101 ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
102 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
103 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
104 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
105 zwlr_layer_surface_v1_set_exclusive_zone(surface->layer_surface, -1);
106 zwlr_layer_surface_v1_set_keyboard_interactivity(
107 surface->layer_surface, true);
108 zwlr_layer_surface_v1_add_listener(surface->layer_surface,
109 &layer_surface_listener, surface);
110 wl_surface_commit(surface->surface);
111}
112
67static void layer_surface_configure(void *data, 113static void layer_surface_configure(void *data,
68 struct zwlr_layer_surface_v1 *layer_surface, 114 struct zwlr_layer_surface_v1 *layer_surface,
69 uint32_t serial, uint32_t width, uint32_t height) { 115 uint32_t serial, uint32_t width, uint32_t height) {
@@ -77,9 +123,7 @@ static void layer_surface_configure(void *data,
77static void layer_surface_closed(void *data, 123static void layer_surface_closed(void *data,
78 struct zwlr_layer_surface_v1 *layer_surface) { 124 struct zwlr_layer_surface_v1 *layer_surface) {
79 struct swaylock_surface *surface = data; 125 struct swaylock_surface *surface = data;
80 zwlr_layer_surface_v1_destroy(surface->layer_surface); 126 destroy_surface(surface);
81 wl_surface_destroy(surface->surface);
82 surface->state->run_display = false;
83} 127}
84 128
85static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { 129static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
@@ -181,14 +225,27 @@ static void handle_global(void *data, struct wl_registry *registry,
181 surface->state = state; 225 surface->state = state;
182 surface->output = wl_registry_bind(registry, name, 226 surface->output = wl_registry_bind(registry, name,
183 &wl_output_interface, 3); 227 &wl_output_interface, 3);
228 surface->output_global_name = name;
184 wl_output_add_listener(surface->output, &_wl_output_listener, surface); 229 wl_output_add_listener(surface->output, &_wl_output_listener, surface);
185 wl_list_insert(&state->surfaces, &surface->link); 230 wl_list_insert(&state->surfaces, &surface->link);
231
232 if (state->run_display) {
233 create_layer_surface(surface);
234 wl_display_roundtrip(state->display);
235 }
186 } 236 }
187} 237}
188 238
189static void handle_global_remove(void *data, struct wl_registry *registry, 239static void handle_global_remove(void *data, struct wl_registry *registry,
190 uint32_t name) { 240 uint32_t name) {
191 // who cares 241 struct swaylock_state *state = data;
242 struct swaylock_surface *surface;
243 wl_list_for_each(surface, &state->surfaces, link) {
244 if (surface->output_global_name == name) {
245 destroy_surface(surface);
246 break;
247 }
248 }
192} 249}
193 250
194static const struct wl_registry_listener registry_listener = { 251static const struct wl_registry_listener registry_listener = {
@@ -276,7 +333,7 @@ int main(int argc, char **argv) {
276 {0, 0, 0, 0} 333 {0, 0, 0, 0}
277 }; 334 };
278 335
279 const char *usage = 336 const char usage[] =
280 "Usage: swaylock [options...]\n" 337 "Usage: swaylock [options...]\n"
281 "\n" 338 "\n"
282 " -h, --help Show help message and quit.\n" 339 " -h, --help Show help message and quit.\n"
@@ -288,13 +345,13 @@ int main(int argc, char **argv) {
288 " -u, --no-unlock-indicator Disable the unlock indicator.\n" 345 " -u, --no-unlock-indicator Disable the unlock indicator.\n"
289 " -f, --daemonize Detach from the controlling terminal.\n"; 346 " -f, --daemonize Detach from the controlling terminal.\n";
290 347
291 struct swaylock_args args = { 348 state.args = (struct swaylock_args){
292 .mode = BACKGROUND_MODE_SOLID_COLOR, 349 .mode = BACKGROUND_MODE_SOLID_COLOR,
293 .color = 0xFFFFFFFF, 350 .color = 0xFFFFFFFF,
294 .show_indicator = true, 351 .show_indicator = true,
295 }; 352 };
296 state.args = args;
297 wl_list_init(&state.images); 353 wl_list_init(&state.images);
354
298 wlr_log_init(L_DEBUG, NULL); 355 wlr_log_init(L_DEBUG, NULL);
299 356
300 int c; 357 int c;
@@ -369,6 +426,8 @@ int main(int argc, char **argv) {
369 return 0; 426 return 0;
370 } 427 }
371 428
429 zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager);
430
372 if (state.zxdg_output_manager) { 431 if (state.zxdg_output_manager) {
373 struct swaylock_surface *surface; 432 struct swaylock_surface *surface;
374 wl_list_for_each(surface, &state.surfaces, link) { 433 wl_list_for_each(surface, &state.surfaces, link) {
@@ -385,33 +444,9 @@ int main(int argc, char **argv) {
385 444
386 struct swaylock_surface *surface; 445 struct swaylock_surface *surface;
387 wl_list_for_each(surface, &state.surfaces, link) { 446 wl_list_for_each(surface, &state.surfaces, link) {
388 surface->image = select_image(&state, surface); 447 create_layer_surface(surface);
389
390 surface->surface = wl_compositor_create_surface(state.compositor);
391 assert(surface->surface);
392
393 surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
394 state.layer_shell, surface->surface, surface->output,
395 ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen");
396 assert(surface->layer_surface);
397
398 zwlr_layer_surface_v1_set_size(surface->layer_surface, 0, 0);
399 zwlr_layer_surface_v1_set_anchor(surface->layer_surface,
400 ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
401 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
402 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
403 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
404 zwlr_layer_surface_v1_set_exclusive_zone(surface->layer_surface, -1);
405 zwlr_layer_surface_v1_set_keyboard_interactivity(
406 surface->layer_surface, true);
407 zwlr_layer_surface_v1_add_listener(surface->layer_surface,
408 &layer_surface_listener, surface);
409 wl_surface_commit(surface->surface);
410 wl_display_roundtrip(state.display);
411 } 448 }
412 449
413 zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager);
414
415 state.run_display = true; 450 state.run_display = true;
416 while (wl_display_dispatch(state.display) != -1 && state.run_display) { 451 while (wl_display_dispatch(state.display) != -1 && state.run_display) {
417 // This space intentionally left blank 452 // This space intentionally left blank
diff --git a/swaylock/render.c b/swaylock/render.c
index cc40f4e9..05236dea 100644
--- a/swaylock/render.c
+++ b/swaylock/render.c
@@ -17,6 +17,9 @@ void render_frame(struct swaylock_surface *surface) {
17 17
18 int buffer_width = surface->width * surface->scale; 18 int buffer_width = surface->width * surface->scale;
19 int buffer_height = surface->height * surface->scale; 19 int buffer_height = surface->height * surface->scale;
20 if (buffer_width == 0 || buffer_height == 0) {
21 return; // not yet configured
22 }
20 23
21 surface->current_buffer = get_next_buffer(state->shm, 24 surface->current_buffer = get_next_buffer(state->shm,
22 surface->buffers, buffer_width, buffer_height); 25 surface->buffers, buffer_width, buffer_height);