diff options
-rw-r--r-- | sway/tree/view.c | 138 |
1 files changed, 75 insertions, 63 deletions
diff --git a/sway/tree/view.c b/sway/tree/view.c index 82c3ad4a..fec628e1 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -476,97 +476,112 @@ void view_execute_criteria(struct sway_view *view) { | |||
476 | seat_set_focus(seat, prior_focus); | 476 | seat_set_focus(seat, prior_focus); |
477 | } | 477 | } |
478 | 478 | ||
479 | static bool should_focus(struct sway_view *view) { | 479 | static struct sway_container *select_workspace(struct sway_view *view) { |
480 | // If the view is the only one in the focused workspace, it'll get focus | ||
481 | // regardless of any no_focus criteria. | ||
482 | struct sway_container *parent = view->swayc->parent; | ||
483 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 480 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
484 | if (parent->type == C_WORKSPACE && seat_get_focus(seat) == parent) { | 481 | |
485 | size_t num_children = parent->children->length + | 482 | // Check if there's any `assign` criteria for the view |
486 | parent->sway_workspace->floating->children->length; | 483 | list_t *criterias = criteria_for_view(view, |
487 | if (num_children == 1) { | 484 | CT_ASSIGN_WORKSPACE | CT_ASSIGN_OUTPUT); |
488 | return true; | 485 | struct sway_container *ws = NULL; |
486 | for (int i = 0; i < criterias->length; ++i) { | ||
487 | struct criteria *criteria = criterias->items[i]; | ||
488 | if (criteria->type == CT_ASSIGN_WORKSPACE) { | ||
489 | struct sway_container *ws = workspace_by_name(criteria->target); | ||
490 | if (!ws) { | ||
491 | ws = workspace_create(NULL, criteria->target); | ||
492 | } | ||
493 | break; | ||
494 | } else { | ||
495 | // CT_ASSIGN_OUTPUT | ||
496 | struct sway_container *output = output_by_name(criteria->target); | ||
497 | if (output) { | ||
498 | ws = seat_get_active_child(seat, output); | ||
499 | break; | ||
500 | } | ||
489 | } | 501 | } |
490 | } | 502 | } |
491 | |||
492 | // Check no_focus criteria | ||
493 | list_t *criterias = criteria_for_view(view, CT_NO_FOCUS); | ||
494 | size_t len = criterias->length; | ||
495 | list_free(criterias); | 503 | list_free(criterias); |
496 | return len == 0; | 504 | if (ws) { |
497 | } | 505 | return ws; |
498 | |||
499 | void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | ||
500 | if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { | ||
501 | return; | ||
502 | } | 506 | } |
503 | 507 | ||
508 | // Check if there's a PID mapping | ||
504 | pid_t pid; | 509 | pid_t pid; |
505 | #ifdef HAVE_XWAYLAND | 510 | #ifdef HAVE_XWAYLAND |
506 | if (view->type == SWAY_VIEW_XWAYLAND) { | 511 | if (view->type == SWAY_VIEW_XWAYLAND) { |
507 | struct wlr_xwayland_surface *surf = | 512 | struct wlr_xwayland_surface *surf = |
508 | wlr_xwayland_surface_from_wlr_surface(wlr_surface); | 513 | wlr_xwayland_surface_from_wlr_surface(view->surface); |
509 | pid = surf->pid; | 514 | pid = surf->pid; |
510 | } else { | 515 | } else { |
511 | struct wl_client *client = | 516 | struct wl_client *client = |
512 | wl_resource_get_client(wlr_surface->resource); | 517 | wl_resource_get_client(view->surface->resource); |
513 | wl_client_get_credentials(client, &pid, NULL, NULL); | 518 | wl_client_get_credentials(client, &pid, NULL, NULL); |
514 | } | 519 | } |
515 | #else | 520 | #else |
516 | struct wl_client *client = | 521 | struct wl_client *client = |
517 | wl_resource_get_client(wlr_surface->resource); | 522 | wl_resource_get_client(view->surface->resource); |
518 | wl_client_get_credentials(client, &pid, NULL, NULL); | 523 | wl_client_get_credentials(client, &pid, NULL, NULL); |
519 | #endif | 524 | #endif |
525 | ws = workspace_for_pid(pid); | ||
526 | if (ws) { | ||
527 | return ws; | ||
528 | } | ||
520 | 529 | ||
530 | // Use the focused workspace | ||
531 | ws = seat_get_focus(seat); | ||
532 | if (ws->type != C_WORKSPACE) { | ||
533 | ws = container_parent(ws, C_WORKSPACE); | ||
534 | } | ||
535 | return ws; | ||
536 | } | ||
537 | |||
538 | static bool should_focus(struct sway_view *view) { | ||
521 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 539 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
522 | struct sway_container *target_sibling = | 540 | struct sway_container *prev_focus = seat_get_focus(seat); |
523 | seat_get_focus_inactive(seat, &root_container); | 541 | struct sway_container *prev_ws = prev_focus->type == C_WORKSPACE ? |
524 | struct sway_container *prev_focus = target_sibling; | 542 | prev_focus : container_parent(prev_focus, C_WORKSPACE); |
525 | struct sway_container *cont = NULL; | 543 | struct sway_container *map_ws = container_parent(view->swayc, C_WORKSPACE); |
526 | 544 | ||
527 | // Check if there's any `assign` criteria for the view | 545 | // Views can only take focus if they are mapped into the active workspace |
528 | list_t *criterias = criteria_for_view(view, | 546 | if (prev_ws != map_ws) { |
529 | CT_ASSIGN_WORKSPACE | CT_ASSIGN_OUTPUT); | 547 | return false; |
530 | struct sway_container *workspace = NULL; | 548 | } |
531 | if (criterias->length) { | 549 | |
532 | struct criteria *criteria = criterias->items[0]; | 550 | // If the view is the only one in the focused workspace, it'll get focus |
533 | if (criteria->type == CT_ASSIGN_WORKSPACE) { | 551 | // regardless of any no_focus criteria. |
534 | workspace = workspace_by_name(criteria->target); | 552 | struct sway_container *parent = view->swayc->parent; |
535 | if (!workspace) { | 553 | if (parent->type == C_WORKSPACE && prev_focus == parent) { |
536 | workspace = workspace_create(NULL, criteria->target); | 554 | size_t num_children = parent->children->length + |
537 | } | 555 | parent->sway_workspace->floating->children->length; |
538 | prev_focus = target_sibling; | 556 | if (num_children == 1) { |
539 | target_sibling = seat_get_focus_inactive(seat, workspace); | 557 | return true; |
540 | } else { | ||
541 | // CT_ASSIGN_OUTPUT | ||
542 | struct sway_container *output = output_by_name(criteria->target); | ||
543 | if (output) { | ||
544 | prev_focus = seat_get_focus_inactive(seat, output); | ||
545 | } | ||
546 | } | 558 | } |
547 | } | 559 | } |
560 | |||
561 | // Check no_focus criteria | ||
562 | list_t *criterias = criteria_for_view(view, CT_NO_FOCUS); | ||
563 | size_t len = criterias->length; | ||
548 | list_free(criterias); | 564 | list_free(criterias); |
565 | return len == 0; | ||
566 | } | ||
549 | 567 | ||
550 | if (!workspace) { | 568 | void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { |
551 | workspace = workspace_for_pid(pid); | 569 | if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { |
552 | if (workspace) { | 570 | return; |
553 | prev_focus = target_sibling; | ||
554 | target_sibling = seat_get_focus_inactive(seat, workspace); | ||
555 | } | ||
556 | } | 571 | } |
572 | view->surface = wlr_surface; | ||
573 | |||
574 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
575 | struct sway_container *ws = select_workspace(view); | ||
576 | struct sway_container *target_sibling = seat_get_focus_inactive(seat, ws); | ||
577 | |||
557 | // If we're about to launch the view into the floating container, then | 578 | // If we're about to launch the view into the floating container, then |
558 | // launch it as a tiled view in the root of the workspace instead. | 579 | // launch it as a tiled view in the root of the workspace instead. |
559 | if (container_is_floating(target_sibling)) { | 580 | if (container_is_floating(target_sibling)) { |
560 | if (prev_focus == target_sibling) { | ||
561 | prev_focus = target_sibling->parent->parent; | ||
562 | } | ||
563 | target_sibling = target_sibling->parent->parent; | 581 | target_sibling = target_sibling->parent->parent; |
564 | } | 582 | } |
565 | 583 | ||
566 | cont = container_view_create(target_sibling, view); | 584 | view->swayc = container_view_create(target_sibling, view); |
567 | |||
568 | view->surface = wlr_surface; | ||
569 | view->swayc = cont; | ||
570 | 585 | ||
571 | view_init_subsurfaces(view, wlr_surface); | 586 | view_init_subsurfaces(view, wlr_surface); |
572 | wl_signal_add(&wlr_surface->events.new_subsurface, | 587 | wl_signal_add(&wlr_surface->events.new_subsurface, |
@@ -586,11 +601,8 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
586 | view_set_tiled(view, true); | 601 | view_set_tiled(view, true); |
587 | } | 602 | } |
588 | 603 | ||
589 | if (should_focus(view) && prev_focus == target_sibling) { | 604 | if (should_focus(view)) { |
590 | input_manager_set_focus(input_manager, cont); | 605 | input_manager_set_focus(input_manager, view->swayc); |
591 | if (workspace) { | ||
592 | workspace_switch(workspace); | ||
593 | } | ||
594 | } | 606 | } |
595 | 607 | ||
596 | view_update_title(view, false); | 608 | view_update_title(view, false); |