aboutsummaryrefslogtreecommitdiff
path: root/sway/tree
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree')
-rw-r--r--sway/tree/container.c2
-rw-r--r--sway/tree/layout.c3
-rw-r--r--sway/tree/view.c59
-rw-r--r--sway/tree/workspace.c271
4 files changed, 250 insertions, 85 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 4f743c40..b56b4e87 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -527,10 +527,12 @@ static struct sway_container *container_at_view(struct sway_container *swayc,
double _sx, _sy;
struct wlr_surface *_surface = NULL;
switch (sview->type) {
+#ifdef HAVE_XWAYLAND
case SWAY_VIEW_XWAYLAND:
_surface = wlr_surface_surface_at(sview->surface,
view_sx, view_sy, &_sx, &_sy);
break;
+#endif
case SWAY_VIEW_XDG_SHELL_V6:
_surface = wlr_xdg_surface_v6_surface_at(
sview->wlr_xdg_surface_v6,
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index a2be0ef3..2b3263f8 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -6,6 +6,7 @@
#include <string.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h>
+#include "config.h"
#include "sway/debug.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
@@ -39,7 +40,9 @@ void layout_init(void) {
root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
root_container.sway_root->output_layout = wlr_output_layout_create();
wl_list_init(&root_container.sway_root->outputs);
+#ifdef HAVE_XWAYLAND
wl_list_init(&root_container.sway_root->xwayland_unmanaged);
+#endif
wl_list_init(&root_container.sway_root->drag_icons);
wl_signal_init(&root_container.sway_root->events.new_container);
root_container.sway_root->scratchpad = create_list();
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 9d88d7aa..beeb8144 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -3,6 +3,10 @@
#include <wayland-server.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_output_layout.h>
+#include "config.h"
+#ifdef HAVE_XWAYLAND
+#include <wlr/xwayland.h>
+#endif
#include "list.h"
#include "log.h"
#include "sway/criteria.h"
@@ -107,14 +111,14 @@ const char *view_get_instance(struct sway_view *view) {
}
return NULL;
}
-
+#ifdef HAVE_XWAYLAND
uint32_t view_get_x11_window_id(struct sway_view *view) {
if (view->impl->get_int_prop) {
return view->impl->get_int_prop(view, VIEW_PROP_X11_WINDOW_ID);
}
return 0;
}
-
+#endif
const char *view_get_window_role(struct sway_view *view) {
if (view->impl->get_string_prop) {
return view->impl->get_string_prop(view, VIEW_PROP_WINDOW_ROLE);
@@ -135,8 +139,10 @@ const char *view_get_shell(struct sway_view *view) {
return "xdg_shell_v6";
case SWAY_VIEW_XDG_SHELL:
return "xdg_shell";
+#ifdef HAVE_XWAYLAND
case SWAY_VIEW_XWAYLAND:
return "xwayland";
+#endif
}
return "unknown";
}
@@ -561,9 +567,27 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
return;
}
+ 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);
+ pid = surf->pid;
+ } else {
+ struct wl_client *client =
+ wl_resource_get_client(wlr_surface->resource);
+ wl_client_get_credentials(client, &pid, NULL, NULL);
+ }
+#else
+ struct wl_client *client =
+ wl_resource_get_client(wlr_surface->resource);
+ wl_client_get_credentials(client, &pid, NULL, NULL);
+#endif
+
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus =
+ struct sway_container *target_sibling =
seat_get_focus_inactive(seat, &root_container);
+ struct sway_container *prev_focus = target_sibling;
struct sway_container *cont = NULL;
// Check if there's any `assign` criteria for the view
@@ -577,22 +601,35 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
if (!workspace) {
workspace = workspace_create(NULL, criteria->target);
}
- focus = seat_get_focus_inactive(seat, workspace);
+ 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) {
- focus = seat_get_focus_inactive(seat, output);
+ prev_focus = seat_get_focus_inactive(seat, output);
}
}
}
+ list_free(criterias);
+
+ if (!workspace) {
+ workspace = workspace_for_pid(pid);
+ if (workspace) {
+ prev_focus = target_sibling;
+ target_sibling = seat_get_focus_inactive(seat, workspace);
+ }
+ }
// 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(focus)) {
- focus = focus->parent->parent;
+ if (container_is_floating(target_sibling)) {
+ if (prev_focus == target_sibling) {
+ prev_focus = target_sibling->parent->parent;
+ }
+ target_sibling = target_sibling->parent->parent;
}
- list_free(criterias);
- cont = container_view_create(focus, view);
+
+ cont = container_view_create(target_sibling, view);
view->surface = wlr_surface;
view->swayc = cont;
@@ -615,7 +652,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
view_set_tiled(view, true);
}
- if (should_focus(view)) {
+ if (should_focus(view) && prev_focus == target_sibling) {
input_manager_set_focus(input_manager, cont);
if (workspace) {
workspace_switch(workspace);
@@ -799,11 +836,13 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
wlr_xdg_surface_v6_from_wlr_surface(wlr_surface);
return view_from_wlr_xdg_surface_v6(xdg_surface_v6);
}
+#ifdef HAVE_XWAYLAND
if (wlr_surface_is_xwayland_surface(wlr_surface)) {
struct wlr_xwayland_surface *xsurface =
wlr_xwayland_surface_from_wlr_surface(wlr_surface);
return view_from_wlr_xwayland_surface(xsurface);
}
+#endif
if (wlr_surface_is_subsurface(wlr_surface)) {
struct wlr_subsurface *subsurface =
wlr_subsurface_from_wlr_surface(wlr_surface);
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 622f01ec..62974cd7 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -9,6 +9,7 @@
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/ipc-server.h"
+#include "sway/output.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
#include "sway/tree/view.h"
@@ -107,96 +108,103 @@ static bool workspace_valid_on_output(const char *output_name,
return true;
}
-char *workspace_next_name(const char *output_name) {
- wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s",
- output_name);
- // Scan all workspace bindings to find the next available workspace name,
- // if none are found/available then default to a number
- struct sway_mode *mode = config->current_mode;
+static void workspace_name_from_binding(const struct sway_binding * binding,
+ const char* output_name, int *min_order, char **earliest_name) {
+ char *cmdlist = strdup(binding->command);
+ char *dup = cmdlist;
+ char *name = NULL;
- // TODO: iterate over keycode bindings too
- int order = INT_MAX;
- char *target = NULL;
- for (int i = 0; i < mode->keysym_bindings->length; ++i) {
- struct sway_binding *binding = mode->keysym_bindings->items[i];
- char *cmdlist = strdup(binding->command);
- char *dup = cmdlist;
- char *name = NULL;
-
- // workspace n
- char *cmd = argsep(&cmdlist, " ");
- if (cmdlist) {
- name = argsep(&cmdlist, ",;");
- }
+ // workspace n
+ char *cmd = argsep(&cmdlist, " ");
+ if (cmdlist) {
+ name = argsep(&cmdlist, ",;");
+ }
- if (strcmp("workspace", cmd) == 0 && name) {
- char *_target = strdup(name);
- _target = do_var_replacement(_target);
- strip_quotes(_target);
- while (isspace(*_target)) {
- memmove(_target, _target+1, strlen(_target+1));
- }
- wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'",
- _target);
+ if (strcmp("workspace", cmd) == 0 && name) {
+ char *_target = strdup(name);
+ _target = do_var_replacement(_target);
+ strip_quotes(_target);
+ while (isspace(*_target)) {
+ memmove(_target, _target+1, strlen(_target+1));
+ }
+ wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'",
+ _target);
- // Make sure that the command references an actual workspace
- // not a command about workspaces
- if (strcmp(_target, "next") == 0 ||
+ // Make sure that the command references an actual workspace
+ // not a command about workspaces
+ if (strcmp(_target, "next") == 0 ||
strcmp(_target, "prev") == 0 ||
strcmp(_target, "next_on_output") == 0 ||
strcmp(_target, "prev_on_output") == 0 ||
strcmp(_target, "number") == 0 ||
strcmp(_target, "back_and_forth") == 0 ||
- strcmp(_target, "current") == 0)
- {
- free(_target);
- free(dup);
- continue;
- }
-
- // If the command is workspace number <name>, isolate the name
- if (strncmp(_target, "number ", strlen("number ")) == 0) {
- size_t length = strlen(_target) - strlen("number ") + 1;
- char *temp = malloc(length);
- strncpy(temp, _target + strlen("number "), length - 1);
- temp[length - 1] = '\0';
- free(_target);
- _target = temp;
- wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target);
-
- // Make sure the workspace number doesn't already exist
- if (workspace_by_number(_target)) {
- free(_target);
- free(dup);
- continue;
- }
- }
+ strcmp(_target, "current") == 0) {
+ free(_target);
+ free(dup);
+ return;
+ }
- // Make sure that the workspace doesn't already exist
- if (workspace_by_name(_target)) {
+ // If the command is workspace number <name>, isolate the name
+ if (strncmp(_target, "number ", strlen("number ")) == 0) {
+ size_t length = strlen(_target) - strlen("number ") + 1;
+ char *temp = malloc(length);
+ strncpy(temp, _target + strlen("number "), length - 1);
+ temp[length - 1] = '\0';
+ free(_target);
+ _target = temp;
+ wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target);
+
+ // Make sure the workspace number doesn't already exist
+ if (workspace_by_number(_target)) {
free(_target);
free(dup);
- continue;
+ return;
}
+ }
- // make sure that the workspace can appear on the given
- // output
- if (!workspace_valid_on_output(output_name, _target)) {
- free(_target);
- free(dup);
- continue;
- }
+ // Make sure that the workspace doesn't already exist
+ if (workspace_by_name(_target)) {
+ free(_target);
+ free(dup);
+ return;
+ }
- if (binding->order < order) {
- order = binding->order;
- free(target);
- target = _target;
- wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target);
- } else {
- free(_target);
- }
+ // make sure that the workspace can appear on the given
+ // output
+ if (!workspace_valid_on_output(output_name, _target)) {
+ free(_target);
+ free(dup);
+ return;
+ }
+
+ if (binding->order < *min_order) {
+ *min_order = binding->order;
+ free(*earliest_name);
+ *earliest_name = _target;
+ wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target);
+ } else {
+ free(_target);
}
- free(dup);
+ }
+ free(dup);
+}
+
+char *workspace_next_name(const char *output_name) {
+ wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s",
+ output_name);
+ // Scan all workspace bindings to find the next available workspace name,
+ // if none are found/available then default to a number
+ struct sway_mode *mode = config->current_mode;
+
+ int order = INT_MAX;
+ char *target = NULL;
+ for (int i = 0; i < mode->keysym_bindings->length; ++i) {
+ workspace_name_from_binding(mode->keysym_bindings->items[i],
+ output_name, &order, &target);
+ }
+ for (int i = 0; i < mode->keycode_bindings->length; ++i) {
+ workspace_name_from_binding(mode->keycode_bindings->items[i],
+ output_name, &order, &target);
}
if (target != NULL) {
return target;
@@ -529,3 +537,116 @@ void workspace_detect_urgent(struct sway_container *workspace) {
container_damage_whole(workspace);
}
}
+
+struct pid_workspace {
+ pid_t pid;
+ char *workspace;
+ struct timespec time_added;
+
+ struct sway_container *output;
+ struct wl_listener output_destroy;
+
+ struct wl_list link;
+};
+
+static struct wl_list pid_workspaces;
+
+struct sway_container *workspace_for_pid(pid_t pid) {
+ if (!pid_workspaces.prev && !pid_workspaces.next) {
+ wl_list_init(&pid_workspaces);
+ return NULL;
+ }
+
+ struct sway_container *ws = NULL;
+ struct pid_workspace *pw = NULL;
+
+ wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid);
+
+ do {
+ struct pid_workspace *_pw = NULL;
+ wl_list_for_each(_pw, &pid_workspaces, link) {
+ if (pid == _pw->pid) {
+ pw = _pw;
+ wlr_log(WLR_DEBUG,
+ "found pid_workspace for pid %d, workspace %s",
+ pid, pw->workspace);
+ goto found;
+ }
+ }
+ pid = get_parent_pid(pid);
+ } while (pid > 1);
+found:
+
+ if (pw && pw->workspace) {
+ ws = workspace_by_name(pw->workspace);
+
+ if (!ws) {
+ wlr_log(WLR_DEBUG,
+ "Creating workspace %s for pid %d because it disappeared",
+ pw->workspace, pid);
+ ws = workspace_create(pw->output, pw->workspace);
+ }
+
+ wl_list_remove(&pw->output_destroy.link);
+ wl_list_remove(&pw->link);
+ free(pw->workspace);
+ free(pw);
+ }
+
+ return ws;
+}
+
+static void pw_handle_output_destroy(struct wl_listener *listener, void *data) {
+ struct pid_workspace *pw = wl_container_of(listener, pw, output_destroy);
+ pw->output = NULL;
+ wl_list_remove(&pw->output_destroy.link);
+ wl_list_init(&pw->output_destroy.link);
+}
+
+void workspace_record_pid(pid_t pid) {
+ wlr_log(WLR_DEBUG, "Recording workspace for process %d", pid);
+ if (!pid_workspaces.prev && !pid_workspaces.next) {
+ wl_list_init(&pid_workspaces);
+ }
+
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ struct sway_container *ws =
+ seat_get_focus_inactive(seat, &root_container);
+ if (ws && ws->type != C_WORKSPACE) {
+ ws = container_parent(ws, C_WORKSPACE);
+ }
+ if (!ws) {
+ wlr_log(WLR_DEBUG, "Bailing out, no workspace");
+ return;
+ }
+ struct sway_container *output = ws->parent;
+ if (!output) {
+ wlr_log(WLR_DEBUG, "Bailing out, no output");
+ return;
+ }
+
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ // Remove expired entries
+ static const int timeout = 60;
+ struct pid_workspace *old, *_old;
+ wl_list_for_each_safe(old, _old, &pid_workspaces, link) {
+ if (now.tv_sec - old->time_added.tv_sec >= timeout) {
+ wl_list_remove(&old->output_destroy.link);
+ wl_list_remove(&old->link);
+ free(old->workspace);
+ free(old);
+ }
+ }
+
+ struct pid_workspace *pw = calloc(1, sizeof(struct pid_workspace));
+ pw->workspace = strdup(ws->name);
+ pw->output = output;
+ pw->pid = pid;
+ memcpy(&pw->time_added, &now, sizeof(struct timespec));
+ pw->output_destroy.notify = pw_handle_output_destroy;
+ wl_signal_add(&output->sway_output->wlr_output->events.destroy,
+ &pw->output_destroy);
+ wl_list_insert(&pid_workspaces, &pw->link);
+}