aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/view.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/view.c')
-rw-r--r--sway/tree/view.c191
1 files changed, 158 insertions, 33 deletions
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 24fb6864..a55c8a29 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -26,6 +26,7 @@ void view_init(struct sway_view *view, enum sway_view_type type,
26 view->impl = impl; 26 view->impl = impl;
27 view->executed_criteria = create_list(); 27 view->executed_criteria = create_list();
28 view->marks = create_list(); 28 view->marks = create_list();
29 view->allow_request_urgent = true;
29 wl_signal_init(&view->events.unmap); 30 wl_signal_init(&view->events.unmap);
30} 31}
31 32
@@ -141,6 +142,19 @@ const char *view_get_shell(struct sway_view *view) {
141 return "unknown"; 142 return "unknown";
142} 143}
143 144
145void view_get_constraints(struct sway_view *view, double *min_width,
146 double *max_width, double *min_height, double *max_height) {
147 if (view->impl->get_constraints) {
148 view->impl->get_constraints(view,
149 min_width, max_width, min_height, max_height);
150 } else {
151 *min_width = DBL_MIN;
152 *max_width = DBL_MAX;
153 *min_height = DBL_MIN;
154 *max_height = DBL_MAX;
155 }
156}
157
144uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, 158uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
145 int height) { 159 int height) {
146 if (view->impl->configure) { 160 if (view->impl->configure) {
@@ -151,12 +165,43 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
151 165
152void view_init_floating(struct sway_view *view) { 166void view_init_floating(struct sway_view *view) {
153 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); 167 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
154 int max_width = ws->width * 0.6666; 168 int min_width, min_height;
155 int max_height = ws->height * 0.6666; 169 int max_width, max_height;
156 view->width = 170
157 view->natural_width > max_width ? max_width : view->natural_width; 171 if (config->floating_minimum_width == -1) { // no minimum
158 view->height = 172 min_width = 0;
159 view->natural_height > max_height ? max_height : view->natural_height; 173 } else if (config->floating_minimum_width == 0) { // automatic
174 min_width = 75;
175 } else {
176 min_width = config->floating_minimum_width;
177 }
178
179 if (config->floating_minimum_height == -1) { // no minimum
180 min_height = 0;
181 } else if (config->floating_minimum_height == 0) { // automatic
182 min_height = 50;
183 } else {
184 min_height = config->floating_minimum_height;
185 }
186
187 if (config->floating_maximum_width == -1) { // no maximum
188 max_width = INT_MAX;
189 } else if (config->floating_maximum_width == 0) { // automatic
190 max_width = ws->width * 0.6666;
191 } else {
192 max_width = config->floating_maximum_width;
193 }
194
195 if (config->floating_maximum_height == -1) { // no maximum
196 max_height = INT_MAX;
197 } else if (config->floating_maximum_height == 0) { // automatic
198 max_height = ws->height * 0.6666;
199 } else {
200 max_height = config->floating_maximum_height;
201 }
202
203 view->width = fmax(min_width, fmin(view->natural_width, max_width));
204 view->height = fmax(min_height, fmin(view->natural_height, max_height));
160 view->x = ws->x + (ws->width - view->width) / 2; 205 view->x = ws->x + (ws->width - view->width) / 2;
161 view->y = ws->y + (ws->height - view->height) / 2; 206 view->y = ws->y + (ws->height - view->height) / 2;
162 207
@@ -165,9 +210,6 @@ void view_init_floating(struct sway_view *view) {
165 view->border_left = view->border_right = true; 210 view->border_left = view->border_right = true;
166 211
167 container_set_geometry_from_floating_view(view->swayc); 212 container_set_geometry_from_floating_view(view->swayc);
168
169 // Don't maximize floating windows
170 view_set_tiled(view, false);
171} 213}
172 214
173void view_autoconfigure(struct sway_view *view) { 215void view_autoconfigure(struct sway_view *view) {
@@ -279,7 +321,6 @@ void view_autoconfigure(struct sway_view *view) {
279 view->y = y; 321 view->y = y;
280 view->width = width; 322 view->width = width;
281 view->height = height; 323 view->height = height;
282 view_set_tiled(view, true);
283} 324}
284 325
285void view_set_activated(struct sway_view *view, bool activated) { 326void view_set_activated(struct sway_view *view, bool activated) {
@@ -289,7 +330,15 @@ void view_set_activated(struct sway_view *view, bool activated) {
289} 330}
290 331
291void view_set_tiled(struct sway_view *view, bool tiled) { 332void view_set_tiled(struct sway_view *view, bool tiled) {
292 view->border = tiled ? config->border : B_NONE; 333 if (!tiled) {
334 view->using_csd = true;
335 if (view->impl->has_client_side_decorations) {
336 view->using_csd = view->impl->has_client_side_decorations(view);
337 }
338 } else {
339 view->using_csd = false;
340 }
341
293 if (view->impl->set_tiled) { 342 if (view->impl->set_tiled) {
294 view->impl->set_tiled(view, tiled); 343 view->impl->set_tiled(view, tiled);
295 } 344 }
@@ -352,6 +401,8 @@ void view_set_fullscreen(struct sway_view *view, bool fullscreen) {
352 } 401 }
353 } 402 }
354 403
404 container_end_mouse_operation(view->swayc);
405
355 ipc_event_window(view->swayc, "fullscreen_mode"); 406 ipc_event_window(view->swayc, "fullscreen_mode");
356} 407}
357 408
@@ -467,27 +518,45 @@ void view_execute_criteria(struct sway_view *view) {
467 list_t *criterias = criteria_for_view(view, CT_COMMAND); 518 list_t *criterias = criteria_for_view(view, CT_COMMAND);
468 for (int i = 0; i < criterias->length; i++) { 519 for (int i = 0; i < criterias->length; i++) {
469 struct criteria *criteria = criterias->items[i]; 520 struct criteria *criteria = criterias->items[i];
470 wlr_log(L_DEBUG, "Checking criteria %s", criteria->raw); 521 wlr_log(WLR_DEBUG, "Checking criteria %s", criteria->raw);
471 if (view_has_executed_criteria(view, criteria)) { 522 if (view_has_executed_criteria(view, criteria)) {
472 wlr_log(L_DEBUG, "Criteria already executed"); 523 wlr_log(WLR_DEBUG, "Criteria already executed");
473 continue; 524 continue;
474 } 525 }
475 wlr_log(L_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", 526 wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
476 criteria->raw, view, criteria->cmdlist); 527 criteria->raw, view, criteria->cmdlist);
528 seat_set_focus(seat, view->swayc);
477 list_add(view->executed_criteria, criteria); 529 list_add(view->executed_criteria, criteria);
478 struct cmd_results *res = execute_command(criteria->cmdlist, NULL); 530 struct cmd_results *res = execute_command(criteria->cmdlist, NULL);
479 if (res->status != CMD_SUCCESS) { 531 if (res->status != CMD_SUCCESS) {
480 wlr_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); 532 wlr_log(WLR_ERROR, "Command '%s' failed: %s", res->input, res->error);
481 } 533 }
482 free_cmd_results(res); 534 free_cmd_results(res);
483 // view must be focused for commands to affect it,
484 // so always refocus in-between command lists
485 seat_set_focus(seat, view->swayc);
486 } 535 }
487 list_free(criterias); 536 list_free(criterias);
488 seat_set_focus(seat, prior_focus); 537 seat_set_focus(seat, prior_focus);
489} 538}
490 539
540static bool should_focus(struct sway_view *view) {
541 // If the view is the only one in the focused workspace, it'll get focus
542 // regardless of any no_focus criteria.
543 struct sway_container *parent = view->swayc->parent;
544 struct sway_seat *seat = input_manager_current_seat(input_manager);
545 if (parent->type == C_WORKSPACE && seat_get_focus(seat) == parent) {
546 size_t num_children = parent->children->length +
547 parent->sway_workspace->floating->children->length;
548 if (num_children == 1) {
549 return true;
550 }
551 }
552
553 // Check no_focus criteria
554 list_t *criterias = criteria_for_view(view, CT_NO_FOCUS);
555 size_t len = criterias->length;
556 list_free(criterias);
557 return len == 0;
558}
559
491void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { 560void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
492 if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { 561 if (!sway_assert(view->surface == NULL, "cannot map mapped view")) {
493 return; 562 return;
@@ -524,7 +593,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
524 prev_focus = target_sibling; 593 prev_focus = target_sibling;
525 target_sibling = seat_get_focus_inactive(seat, workspace); 594 target_sibling = seat_get_focus_inactive(seat, workspace);
526 } else { 595 } else {
527 // TODO: CT_ASSIGN_OUTPUT 596 // CT_ASSIGN_OUTPUT
597 struct sway_container *output = output_by_name(criteria->target);
598 if (output) {
599 prev_focus = seat_get_focus_inactive(seat, output);
600 }
528 } 601 }
529 } 602 }
530 list_free(criterias); 603 list_free(criterias);
@@ -549,8 +622,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
549 622
550 view->surface = wlr_surface; 623 view->surface = wlr_surface;
551 view->swayc = cont; 624 view->swayc = cont;
552 view->border = config->border;
553 view->border_thickness = config->border_thickness;
554 625
555 view_init_subsurfaces(view, wlr_surface); 626 view_init_subsurfaces(view, wlr_surface);
556 wl_signal_add(&wlr_surface->events.new_subsurface, 627 wl_signal_add(&wlr_surface->events.new_subsurface,
@@ -561,11 +632,20 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
561 view->container_reparent.notify = view_handle_container_reparent; 632 view->container_reparent.notify = view_handle_container_reparent;
562 633
563 if (view->impl->wants_floating && view->impl->wants_floating(view)) { 634 if (view->impl->wants_floating && view->impl->wants_floating(view)) {
635 view->border = config->floating_border;
636 view->border_thickness = config->floating_border_thickness;
564 container_set_floating(view->swayc, true); 637 container_set_floating(view->swayc, true);
638 } else {
639 view->border = config->border;
640 view->border_thickness = config->border_thickness;
641 view_set_tiled(view, true);
565 } 642 }
566 643
567 if (prev_focus == target_sibling) { 644 if (should_focus(view) && prev_focus == target_sibling) {
568 input_manager_set_focus(input_manager, cont); 645 input_manager_set_focus(input_manager, cont);
646 if (workspace) {
647 workspace_switch(workspace);
648 }
569 } 649 }
570 650
571 view_update_title(view, false); 651 view_update_title(view, false);
@@ -581,16 +661,27 @@ void view_unmap(struct sway_view *view) {
581 wl_list_remove(&view->surface_new_subsurface.link); 661 wl_list_remove(&view->surface_new_subsurface.link);
582 wl_list_remove(&view->container_reparent.link); 662 wl_list_remove(&view->container_reparent.link);
583 663
664 if (view->urgent_timer) {
665 wl_event_source_remove(view->urgent_timer);
666 view->urgent_timer = NULL;
667 }
668
669 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
670
671 struct sway_container *parent;
584 if (view->is_fullscreen) { 672 if (view->is_fullscreen) {
585 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
586 ws->sway_workspace->fullscreen = NULL; 673 ws->sway_workspace->fullscreen = NULL;
587 container_destroy(view->swayc); 674 parent = container_destroy(view->swayc);
588 675
589 arrange_and_commit(ws->parent); 676 arrange_windows(ws->parent);
590 } else { 677 } else {
591 struct sway_container *parent = container_destroy(view->swayc); 678 parent = container_destroy(view->swayc);
592 arrange_and_commit(parent); 679 arrange_windows(parent);
680 }
681 if (parent->type >= C_WORKSPACE) { // if the workspace still exists
682 workspace_detect_urgent(ws);
593 } 683 }
684 transaction_commit_dirty();
594 view->surface = NULL; 685 view->surface = NULL;
595} 686}
596 687
@@ -601,6 +692,8 @@ void view_update_position(struct sway_view *view, double lx, double ly) {
601 container_damage_whole(view->swayc); 692 container_damage_whole(view->swayc);
602 view->x = lx; 693 view->x = lx;
603 view->y = ly; 694 view->y = ly;
695 view->swayc->current.view_x = lx;
696 view->swayc->current.view_y = ly;
604 if (container_is_floating(view->swayc)) { 697 if (container_is_floating(view->swayc)) {
605 container_set_geometry_from_floating_view(view->swayc); 698 container_set_geometry_from_floating_view(view->swayc);
606 } 699 }
@@ -614,6 +707,8 @@ void view_update_size(struct sway_view *view, int width, int height) {
614 container_damage_whole(view->swayc); 707 container_damage_whole(view->swayc);
615 view->width = width; 708 view->width = width;
616 view->height = height; 709 view->height = height;
710 view->swayc->current.view_width = width;
711 view->swayc->current.view_height = height;
617 if (container_is_floating(view->swayc)) { 712 if (container_is_floating(view->swayc)) {
618 container_set_geometry_from_floating_view(view->swayc); 713 container_set_geometry_from_floating_view(view->swayc);
619 } 714 }
@@ -624,7 +719,7 @@ static void view_subsurface_create(struct sway_view *view,
624 struct wlr_subsurface *subsurface) { 719 struct wlr_subsurface *subsurface) {
625 struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child)); 720 struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child));
626 if (child == NULL) { 721 if (child == NULL) {
627 wlr_log(L_ERROR, "Allocation failed"); 722 wlr_log(WLR_ERROR, "Allocation failed");
628 return; 723 return;
629 } 724 }
630 view_child_init(child, NULL, view, subsurface->surface); 725 view_child_init(child, NULL, view, subsurface->surface);
@@ -744,8 +839,9 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
744 return NULL; 839 return NULL;
745 } 840 }
746 841
747 wlr_log(L_DEBUG, "Surface of unknown type (role %s): %p", 842 const char *role = wlr_surface->role ? wlr_surface->role->name : NULL;
748 wlr_surface->role, wlr_surface); 843 wlr_log(WLR_DEBUG, "Surface of unknown type (role %s): %p",
844 role, wlr_surface);
749 return NULL; 845 return NULL;
750} 846}
751 847
@@ -812,7 +908,7 @@ static char *escape_title(char *buffer) {
812 char *escaped_title = calloc(length + 1, sizeof(char)); 908 char *escaped_title = calloc(length + 1, sizeof(char));
813 int result = escape_markup_text(buffer, escaped_title, length); 909 int result = escape_markup_text(buffer, escaped_title, length);
814 if (result != length) { 910 if (result != length) {
815 wlr_log(L_ERROR, "Could not escape title: %s", buffer); 911 wlr_log(WLR_ERROR, "Could not escape title: %s", buffer);
816 free(escaped_title); 912 free(escaped_title);
817 return buffer; 913 return buffer;
818 } 914 }
@@ -946,7 +1042,7 @@ static void update_marks_texture(struct sway_view *view,
946 1042
947 double scale = output->sway_output->wlr_output->scale; 1043 double scale = output->sway_output->wlr_output->scale;
948 int width = 0; 1044 int width = 0;
949 int height = config->font_height * scale; 1045 int height = view->swayc->title_height * scale;
950 1046
951 cairo_t *c = cairo_create(NULL); 1047 cairo_t *c = cairo_create(NULL);
952 get_text_size(c, config->font, &width, NULL, scale, false, "%s", buffer); 1048 get_text_size(c, config->font, &width, NULL, scale, false, "%s", buffer);
@@ -995,7 +1091,7 @@ void view_update_marks_textures(struct sway_view *view) {
995} 1091}
996 1092
997bool view_is_visible(struct sway_view *view) { 1093bool view_is_visible(struct sway_view *view) {
998 if (!view->swayc || view->swayc->destroying) { 1094 if (!view->swayc || view->swayc->destroying || !view->swayc->parent) {
999 return false; 1095 return false;
1000 } 1096 }
1001 struct sway_container *workspace = 1097 struct sway_container *workspace =
@@ -1033,3 +1129,32 @@ bool view_is_visible(struct sway_view *view) {
1033 } 1129 }
1034 return true; 1130 return true;
1035} 1131}
1132
1133void view_set_urgent(struct sway_view *view, bool enable) {
1134 if (view_is_urgent(view) == enable) {
1135 return;
1136 }
1137 if (enable) {
1138 struct sway_seat *seat = input_manager_current_seat(input_manager);
1139 if (seat_get_focus(seat) == view->swayc) {
1140 return;
1141 }
1142 clock_gettime(CLOCK_MONOTONIC, &view->urgent);
1143 } else {
1144 view->urgent = (struct timespec){ 0 };
1145 if (view->urgent_timer) {
1146 wl_event_source_remove(view->urgent_timer);
1147 view->urgent_timer = NULL;
1148 }
1149 }
1150 container_damage_whole(view->swayc);
1151
1152 ipc_event_window(view->swayc, "urgent");
1153
1154 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
1155 workspace_detect_urgent(ws);
1156}
1157
1158bool view_is_urgent(struct sway_view *view) {
1159 return view->urgent.tv_sec || view->urgent.tv_nsec;
1160}