Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/sway/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ sway_cmd cmd_exec_process;

sway_cmd cmd_allow_tearing;
sway_cmd cmd_assign;
sway_cmd cmd_assign_parent_workspace;
sway_cmd cmd_bar;
sway_cmd cmd_bindcode;
sway_cmd cmd_bindgesture;
Expand Down
1 change: 1 addition & 0 deletions include/sway/criteria.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum criteria_type {
CT_ASSIGN_WORKSPACE = 1 << 2,
CT_ASSIGN_WORKSPACE_NUMBER = 1 << 3,
CT_NO_FOCUS = 1 << 4,
CT_ASSIGN_PARENT_WORKSPACE = 1 << 5,
};

enum pattern_type {
Expand Down
1 change: 1 addition & 0 deletions sway/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type
/* Keep alphabetized */
static const struct cmd_handler handlers[] = {
{ "assign", cmd_assign },
{ "assign_parent_workspace", cmd_assign_parent_workspace },
{ "bar", cmd_bar },
{ "bindcode", cmd_bindcode },
{ "bindgesture", cmd_bindgesture },
Expand Down
34 changes: 34 additions & 0 deletions sway/commands/assign_parent_workspace.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <string.h>
#include "sway/commands.h"
#include "sway/criteria.h"
#include "list.h"
#include "log.h"

struct cmd_results *cmd_assign_parent_workspace(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "assign_parent_workspace", EXPECTED_AT_LEAST, 1))) {
return error;
}

char *err_str = NULL;
struct criteria *criteria = criteria_parse(argv[0], &err_str);
if (!criteria) {
error = cmd_results_new(CMD_INVALID, "%s", err_str);
free(err_str);
return error;
}

criteria->type = CT_ASSIGN_PARENT_WORKSPACE;

// Check if it already exists
if (criteria_already_exists(criteria)) {
sway_log(SWAY_DEBUG, "assign_parent_workspace already exists: '%s'", criteria->raw);
criteria_destroy(criteria);
return cmd_results_new(CMD_SUCCESS, NULL);
}

list_add(config->criteria, criteria);
sway_log(SWAY_DEBUG, "assign_parent_workspace: '%s' added", criteria->raw);

return cmd_results_new(CMD_SUCCESS, NULL);
}
1 change: 1 addition & 0 deletions sway/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ sway_sources = files(

'commands/allow_tearing.c',
'commands/assign.c',
'commands/assign_parent_workspace.c',
'commands/bar.c',
'commands/bind.c',
'commands/border.c',
Expand Down
47 changes: 46 additions & 1 deletion sway/tree/view.c
Original file line number Diff line number Diff line change
Expand Up @@ -577,12 +577,51 @@ void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx) {
view->ctx = ctx;
}

static struct sway_workspace *get_parent_workspace(struct sway_view *view) {
// Try to get the parent view's workspace for both XDG and XWayland windows
struct sway_view *parent_view = NULL;

// Check for XDG Shell parent
if (view->wlr_xdg_toplevel && view->wlr_xdg_toplevel->parent) {
struct wlr_xdg_surface *parent_surface = view->wlr_xdg_toplevel->parent->base;
if (parent_surface) {
struct sway_view *xdg_parent_view = view_from_wlr_xdg_surface(parent_surface);
if (xdg_parent_view && xdg_parent_view->container) {
parent_view = xdg_parent_view;
}
}
}

#if WLR_HAS_XWAYLAND
// Check for XWayland parent (only for XWayland views!)
if (!parent_view && view->type == SWAY_VIEW_XWAYLAND &&
view->wlr_xwayland_surface && view->wlr_xwayland_surface->parent) {
struct wlr_xwayland_surface *parent_xsurface = view->wlr_xwayland_surface->parent;

// Check if parent surface is mapped and has valid data
if (parent_xsurface->surface && parent_xsurface->surface->mapped && parent_xsurface->data) {
struct sway_view *xw_parent_view = view_from_wlr_xwayland_surface(parent_xsurface);
if (xw_parent_view && xw_parent_view->container) {
parent_view = xw_parent_view;
}
}
}
#endif

// If we found a parent view with a container, return its workspace
if (parent_view && parent_view->container) {
return parent_view->container->pending.workspace;
}

return NULL;
}

static struct sway_workspace *select_workspace(struct sway_view *view) {
struct sway_seat *seat = input_manager_current_seat();

// Check if there's any `assign` criteria for the view
list_t *criterias = criteria_for_view(view,
CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT);
CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT | CT_ASSIGN_PARENT_WORKSPACE);
struct sway_workspace *ws = NULL;
for (int i = 0; i < criterias->length; ++i) {
struct criteria *criteria = criterias->items[i];
Expand All @@ -592,6 +631,12 @@ static struct sway_workspace *select_workspace(struct sway_view *view) {
ws = output_get_active_workspace(output);
break;
}
} else if (criteria->type == CT_ASSIGN_PARENT_WORKSPACE) {
// Assign to parent's workspace if parent exists
ws = get_parent_workspace(view);
if (ws) {
break;
}
} else {
// CT_ASSIGN_WORKSPACE(_NUMBER)
ws = criteria->type == CT_ASSIGN_WORKSPACE_NUMBER ?
Expand Down