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..e641544e 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -476,97 +476,112 @@ void view_execute_criteria(struct sway_view *view) { seat_set_focus(seat, prior_focus); } -static bool should_focus(struct sway_view *view) { - // If the view is the only one in the focused workspace, it'll get focus - // regardless of any no_focus criteria. - struct sway_container *parent = view->swayc->parent; +static struct sway_container *select_workspace(struct sway_view *view) { struct sway_seat *seat = input_manager_current_seat(input_manager); - if (parent->type == C_WORKSPACE && seat_get_focus(seat) == parent) { - size_t num_children = parent->children->length + - parent->sway_workspace->floating->children->length; - if (num_children == 1) { - return true; + + // Check if there's any `assign` criteria for the view + list_t *criterias = criteria_for_view(view, + CT_ASSIGN_WORKSPACE | CT_ASSIGN_OUTPUT); + struct sway_container *ws = NULL; + for (int i = 0; i < criterias->length; ++i) { + struct criteria *criteria = criterias->items[i]; + if (criteria->type == CT_ASSIGN_WORKSPACE) { + ws = workspace_by_name(criteria->target); + if (!ws) { + ws = workspace_create(NULL, criteria->target); + } + break; + } else { + // CT_ASSIGN_OUTPUT + struct sway_container *output = output_by_name(criteria->target); + if (output) { + ws = seat_get_active_child(seat, output); + break; + } } } - - // Check no_focus criteria - list_t *criterias = criteria_for_view(view, CT_NO_FOCUS); - size_t len = criterias->length; list_free(criterias); - return len == 0; -} - -void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { - if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { - return; + if (ws) { + return ws; } + // Check if there's a PID mapping pid_t pid; #ifdef HAVE_XWAYLAND if (view->type == SWAY_VIEW_XWAYLAND) { struct wlr_xwayland_surface *surf = - wlr_xwayland_surface_from_wlr_surface(wlr_surface); + wlr_xwayland_surface_from_wlr_surface(view->surface); pid = surf->pid; } else { struct wl_client *client = - wl_resource_get_client(wlr_surface->resource); + wl_resource_get_client(view->surface->resource); wl_client_get_credentials(client, &pid, NULL, NULL); } #else struct wl_client *client = - wl_resource_get_client(wlr_surface->resource); + wl_resource_get_client(view->surface->resource); wl_client_get_credentials(client, &pid, NULL, NULL); #endif + ws = workspace_for_pid(pid); + if (ws) { + return ws; + } + // Use the focused workspace + ws = seat_get_focus(seat); + if (ws->type != C_WORKSPACE) { + ws = container_parent(ws, C_WORKSPACE); + } + return ws; +} + +static bool should_focus(struct sway_view *view) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *target_sibling = - seat_get_focus_inactive(seat, &root_container); - struct sway_container *prev_focus = target_sibling; - struct sway_container *cont = NULL; + struct sway_container *prev_focus = seat_get_focus(seat); + struct sway_container *prev_ws = prev_focus->type == C_WORKSPACE ? + prev_focus : container_parent(prev_focus, C_WORKSPACE); + struct sway_container *map_ws = container_parent(view->swayc, C_WORKSPACE); - // Check if there's any `assign` criteria for the view - list_t *criterias = criteria_for_view(view, - CT_ASSIGN_WORKSPACE | CT_ASSIGN_OUTPUT); - struct sway_container *workspace = NULL; - if (criterias->length) { - struct criteria *criteria = criterias->items[0]; - if (criteria->type == CT_ASSIGN_WORKSPACE) { - workspace = workspace_by_name(criteria->target); - if (!workspace) { - workspace = workspace_create(NULL, criteria->target); - } - prev_focus = target_sibling; - target_sibling = seat_get_focus_inactive(seat, workspace); - } else { - // CT_ASSIGN_OUTPUT - struct sway_container *output = output_by_name(criteria->target); - if (output) { - prev_focus = seat_get_focus_inactive(seat, output); - } + // Views can only take focus if they are mapped into the active workspace + if (prev_ws != map_ws) { + return false; + } + + // If the view is the only one in the focused workspace, it'll get focus + // regardless of any no_focus criteria. + struct sway_container *parent = view->swayc->parent; + if (parent->type == C_WORKSPACE && prev_focus == parent) { + size_t num_children = parent->children->length + + parent->sway_workspace->floating->children->length; + if (num_children == 1) { + return true; } } + + // Check no_focus criteria + list_t *criterias = criteria_for_view(view, CT_NO_FOCUS); + size_t len = criterias->length; list_free(criterias); + return len == 0; +} - if (!workspace) { - workspace = workspace_for_pid(pid); - if (workspace) { - prev_focus = target_sibling; - target_sibling = seat_get_focus_inactive(seat, workspace); - } +void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { + if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { + return; } + view->surface = wlr_surface; + + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *ws = select_workspace(view); + struct sway_container *target_sibling = seat_get_focus_inactive(seat, ws); + // If we're about to launch the view into the floating container, then // launch it as a tiled view in the root of the workspace instead. if (container_is_floating(target_sibling)) { - if (prev_focus == target_sibling) { - prev_focus = target_sibling->parent->parent; - } target_sibling = target_sibling->parent->parent; } - cont = container_view_create(target_sibling, view); - - view->surface = wlr_surface; - view->swayc = cont; + view->swayc = container_view_create(target_sibling, view); view_init_subsurfaces(view, wlr_surface); wl_signal_add(&wlr_surface->events.new_subsurface, @@ -586,11 +601,8 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { view_set_tiled(view, true); } - if (should_focus(view) && prev_focus == target_sibling) { - input_manager_set_focus(input_manager, cont); - if (workspace) { - workspace_switch(workspace); - } + if (should_focus(view)) { + input_manager_set_focus(input_manager, view->swayc); } view_update_title(view, false); |