mirror of
https://github.com/swaywm/sway.git
synced 2026-04-18 06:46:56 -04:00
Merge e58e542c43 into 131045ce55
This commit is contained in:
commit
80ce65ed7a
9 changed files with 261 additions and 51 deletions
|
|
@ -84,8 +84,9 @@ struct criteria *criteria_parse(char *raw, char **error);
|
||||||
list_t *criteria_for_view(struct sway_view *view, enum criteria_type types);
|
list_t *criteria_for_view(struct sway_view *view, enum criteria_type types);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile a list of containers matching the given criteria.
|
* Compile a list of nodes matching the given criteria.
|
||||||
|
* Returns a list of struct sway_node *.
|
||||||
*/
|
*/
|
||||||
list_t *criteria_get_containers(struct criteria *criteria);
|
list_t *criteria_get_nodes(struct criteria *criteria);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ struct sway_workspace {
|
||||||
list_t *floating; // struct sway_container
|
list_t *floating; // struct sway_container
|
||||||
list_t *tiling; // struct sway_container
|
list_t *tiling; // struct sway_container
|
||||||
list_t *output_priority;
|
list_t *output_priority;
|
||||||
|
list_t *marks; // char *
|
||||||
bool urgent;
|
bool urgent;
|
||||||
|
|
||||||
struct sway_workspace_state current;
|
struct sway_workspace_state current;
|
||||||
|
|
@ -157,4 +158,14 @@ size_t workspace_num_sticky_containers(struct sway_workspace *ws);
|
||||||
*/
|
*/
|
||||||
void workspace_squash(struct sway_workspace *workspace);
|
void workspace_squash(struct sway_workspace *workspace);
|
||||||
|
|
||||||
|
bool workspace_has_mark(struct sway_workspace *ws, char *mark);
|
||||||
|
|
||||||
|
void workspace_add_mark(struct sway_workspace *ws, char *mark);
|
||||||
|
|
||||||
|
void workspace_clear_marks(struct sway_workspace *ws);
|
||||||
|
|
||||||
|
bool workspace_find_and_unmark(char *mark);
|
||||||
|
|
||||||
|
struct sway_workspace *workspace_find_mark(char *mark);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
|
||||||
struct sway_container *con) {
|
struct sway_container *con) {
|
||||||
char *cmd;
|
char *cmd;
|
||||||
char matched_delim = ';';
|
char matched_delim = ';';
|
||||||
list_t *containers = NULL;
|
list_t *nodes = NULL;
|
||||||
bool using_criteria = false;
|
bool using_criteria = false;
|
||||||
|
|
||||||
if (seat == NULL) {
|
if (seat == NULL) {
|
||||||
|
|
@ -241,8 +241,8 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
|
||||||
free(error);
|
free(error);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
list_free(containers);
|
list_free(nodes);
|
||||||
containers = criteria_get_containers(criteria);
|
nodes = criteria_get_nodes(criteria);
|
||||||
head += strlen(criteria->raw);
|
head += strlen(criteria->raw);
|
||||||
criteria_destroy(criteria);
|
criteria_destroy(criteria);
|
||||||
using_criteria = true;
|
using_criteria = true;
|
||||||
|
|
@ -298,14 +298,14 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
|
||||||
free_argv(argc, argv);
|
free_argv(argc, argv);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
} else if (containers->length == 0) {
|
} else if (nodes->length == 0) {
|
||||||
list_add(res_list,
|
list_add(res_list,
|
||||||
cmd_results_new(CMD_FAILURE, "No matching node."));
|
cmd_results_new(CMD_FAILURE, "No matching node."));
|
||||||
} else {
|
} else {
|
||||||
struct cmd_results *fail_res = NULL;
|
struct cmd_results *fail_res = NULL;
|
||||||
for (int i = 0; i < containers->length; ++i) {
|
for (int i = 0; i < nodes->length; ++i) {
|
||||||
struct sway_container *container = containers->items[i];
|
struct sway_node *node = nodes->items[i];
|
||||||
set_config_node(&container->node, true);
|
set_config_node(node, true);
|
||||||
struct cmd_results *res = handler->handle(argc-1, argv+1);
|
struct cmd_results *res = handler->handle(argc-1, argv+1);
|
||||||
if (res->status == CMD_SUCCESS) {
|
if (res->status == CMD_SUCCESS) {
|
||||||
free_cmd_results(res);
|
free_cmd_results(res);
|
||||||
|
|
@ -329,7 +329,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
|
||||||
} while(head);
|
} while(head);
|
||||||
cleanup:
|
cleanup:
|
||||||
free(exec);
|
free(exec);
|
||||||
list_free(containers);
|
list_free(nodes);
|
||||||
return res_list;
|
return res_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/tree/view.h"
|
#include "sway/tree/view.h"
|
||||||
|
#include "sway/tree/workspace.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
|
|
@ -18,8 +19,13 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
struct sway_container *container = config->handler_context.container;
|
struct sway_container *container = config->handler_context.container;
|
||||||
if (!container) {
|
struct sway_workspace *workspace = config->handler_context.workspace;
|
||||||
return cmd_results_new(CMD_INVALID, "Only containers can have marks");
|
|
||||||
|
// If no container but we have a workspace (targeted via con_id criteria),
|
||||||
|
// apply marks to the workspace
|
||||||
|
if (!container && !workspace) {
|
||||||
|
return cmd_results_new(CMD_INVALID,
|
||||||
|
"Only containers and workspaces can have marks");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool add = false, toggle = false;
|
bool add = false, toggle = false;
|
||||||
|
|
@ -44,23 +50,44 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
char *mark = join_args(argv, argc);
|
char *mark = join_args(argv, argc);
|
||||||
bool had_mark = container_has_mark(container, mark);
|
|
||||||
|
|
||||||
if (!add) {
|
if (container) {
|
||||||
// Replacing
|
bool had_mark = container_has_mark(container, mark);
|
||||||
container_clear_marks(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
container_find_and_unmark(mark);
|
if (!add) {
|
||||||
|
// Replacing
|
||||||
|
container_clear_marks(container);
|
||||||
|
}
|
||||||
|
|
||||||
if (!toggle || !had_mark) {
|
container_find_and_unmark(mark);
|
||||||
container_add_mark(container, mark);
|
workspace_find_and_unmark(mark);
|
||||||
}
|
|
||||||
|
|
||||||
free(mark);
|
if (!toggle || !had_mark) {
|
||||||
container_update_marks(container);
|
container_add_mark(container, mark);
|
||||||
if (container->view) {
|
}
|
||||||
view_execute_criteria(container->view);
|
|
||||||
|
free(mark);
|
||||||
|
container_update_marks(container);
|
||||||
|
if (container->view) {
|
||||||
|
view_execute_criteria(container->view);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Workspace
|
||||||
|
bool had_mark = workspace_has_mark(workspace, mark);
|
||||||
|
|
||||||
|
if (!add) {
|
||||||
|
// Replacing
|
||||||
|
workspace_clear_marks(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
container_find_and_unmark(mark);
|
||||||
|
workspace_find_and_unmark(mark);
|
||||||
|
|
||||||
|
if (!toggle || !had_mark) {
|
||||||
|
workspace_add_mark(workspace, mark);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
|
|
||||||
|
|
@ -525,11 +525,17 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
|
||||||
destination = seat_get_focus_inactive(seat, &new_output->node);
|
destination = seat_get_focus_inactive(seat, &new_output->node);
|
||||||
} else if (strcasecmp(argv[0], "mark") == 0) {
|
} else if (strcasecmp(argv[0], "mark") == 0) {
|
||||||
struct sway_container *dest_con = container_find_mark(argv[1]);
|
struct sway_container *dest_con = container_find_mark(argv[1]);
|
||||||
if (dest_con == NULL) {
|
if (dest_con) {
|
||||||
return cmd_results_new(CMD_FAILURE,
|
destination = &dest_con->node;
|
||||||
"Mark '%s' not found", argv[1]);
|
} else {
|
||||||
|
struct sway_workspace *dest_ws = workspace_find_mark(argv[1]);
|
||||||
|
if (dest_ws) {
|
||||||
|
destination = &dest_ws->node;
|
||||||
|
} else {
|
||||||
|
return cmd_results_new(CMD_FAILURE,
|
||||||
|
"Mark '%s' not found", argv[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
destination = &dest_con->node;
|
|
||||||
} else {
|
} else {
|
||||||
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
|
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
|
||||||
}
|
}
|
||||||
|
|
@ -560,8 +566,33 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
|
||||||
root_scratchpad_show(container);
|
root_scratchpad_show(container);
|
||||||
}
|
}
|
||||||
switch (destination->type) {
|
switch (destination->type) {
|
||||||
case N_WORKSPACE:
|
case N_WORKSPACE: {
|
||||||
container_move_to_workspace(container, destination->sway_workspace);
|
struct sway_workspace *dest_ws = destination->sway_workspace;
|
||||||
|
// Match i3's con_move_to_target behavior:
|
||||||
|
// - Empty workspace: move directly to workspace
|
||||||
|
// - Non-empty workspace: descend to focused child, add as sibling
|
||||||
|
// (i3's _con_move_to_con goes up to parent, making con a sibling)
|
||||||
|
if (workspace_is_empty(dest_ws)) {
|
||||||
|
container_move_to_workspace(container, dest_ws);
|
||||||
|
} else {
|
||||||
|
struct sway_node *focus =
|
||||||
|
seat_get_focus_inactive(seat, destination);
|
||||||
|
if (focus && focus->type == N_CONTAINER) {
|
||||||
|
struct sway_container *focus_con = focus->sway_container;
|
||||||
|
// Match i3: add as sibling of focused child, not as child of it
|
||||||
|
if (container != focus_con &&
|
||||||
|
!container_has_ancestor(focus_con, container)) {
|
||||||
|
container_detach(container);
|
||||||
|
container->pending.width = container->pending.height = 0;
|
||||||
|
container->width_fraction = container->height_fraction = 0;
|
||||||
|
container_add_sibling(focus_con, container, 1);
|
||||||
|
if (container->view) {
|
||||||
|
ipc_event_window(container, "move");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case N_OUTPUT: {
|
case N_OUTPUT: {
|
||||||
struct sway_output *output = destination->sway_output;
|
struct sway_output *output = destination->sway_output;
|
||||||
|
|
@ -573,8 +604,32 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
|
||||||
container_move_to_workspace(container, ws);
|
container_move_to_workspace(container, ws);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case N_CONTAINER:
|
case N_CONTAINER: {
|
||||||
container_move_to_container(container, destination->sway_container);
|
struct sway_container *dest_con = destination->sway_container;
|
||||||
|
// Match i3's con_move_to_target behavior:
|
||||||
|
// If destination is a split (not a leaf), descend to focused child
|
||||||
|
// and add as sibling of that child
|
||||||
|
if (!dest_con->view) {
|
||||||
|
struct sway_node *focus =
|
||||||
|
seat_get_focus_inactive(seat, destination);
|
||||||
|
if (focus && focus->type == N_CONTAINER) {
|
||||||
|
struct sway_container *focus_con = focus->sway_container;
|
||||||
|
// Add as sibling of focused child
|
||||||
|
if (container != focus_con &&
|
||||||
|
!container_has_ancestor(focus_con, container)) {
|
||||||
|
container_detach(container);
|
||||||
|
container->pending.width = container->pending.height = 0;
|
||||||
|
container->width_fraction = container->height_fraction = 0;
|
||||||
|
container_add_sibling(focus_con, container, 1);
|
||||||
|
if (container->view) {
|
||||||
|
ipc_event_window(container, "move");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
container_move_to_container(container, dest_con);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case N_ROOT:
|
case N_ROOT:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -3,29 +3,38 @@
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/tree/root.h"
|
#include "sway/tree/root.h"
|
||||||
#include "sway/tree/view.h"
|
#include "sway/tree/view.h"
|
||||||
|
#include "sway/tree/workspace.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
|
|
||||||
static void remove_mark(struct sway_container *con) {
|
static void remove_container_mark(struct sway_container *con) {
|
||||||
container_clear_marks(con);
|
container_clear_marks(con);
|
||||||
container_update_marks(con);
|
container_update_marks(con);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_all_marks_iterator(struct sway_container *con, void *data) {
|
static void remove_all_container_marks_iterator(struct sway_container *con, void *data) {
|
||||||
remove_mark(con);
|
remove_container_mark(con);
|
||||||
}
|
}
|
||||||
|
|
||||||
// unmark Remove all marks from all views
|
static void remove_all_workspace_marks_iterator(struct sway_workspace *ws, void *data) {
|
||||||
// unmark foo Remove single mark from whichever view has it
|
workspace_clear_marks(ws);
|
||||||
// [criteria] unmark Remove all marks from matched view
|
}
|
||||||
// [criteria] unmark foo Remove single mark from matched view
|
|
||||||
|
// unmark Remove all marks from all views/workspaces
|
||||||
|
// unmark foo Remove single mark from whichever view/workspace has it
|
||||||
|
// [criteria] unmark Remove all marks from matched view/workspace
|
||||||
|
// [criteria] unmark foo Remove single mark from matched view/workspace
|
||||||
|
|
||||||
struct cmd_results *cmd_unmark(int argc, char **argv) {
|
struct cmd_results *cmd_unmark(int argc, char **argv) {
|
||||||
// Determine the container
|
// Determine the container or workspace
|
||||||
struct sway_container *con = NULL;
|
struct sway_container *con = NULL;
|
||||||
|
struct sway_workspace *ws = NULL;
|
||||||
if (config->handler_context.node_overridden) {
|
if (config->handler_context.node_overridden) {
|
||||||
con = config->handler_context.container;
|
con = config->handler_context.container;
|
||||||
|
if (!con) {
|
||||||
|
ws = config->handler_context.workspace;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the mark
|
// Determine the mark
|
||||||
|
|
@ -41,13 +50,23 @@ struct cmd_results *cmd_unmark(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
} else if (con && !mark) {
|
} else if (con && !mark) {
|
||||||
// Clear all marks from the given container
|
// Clear all marks from the given container
|
||||||
remove_mark(con);
|
remove_container_mark(con);
|
||||||
} else if (!con && mark) {
|
} else if (ws && mark) {
|
||||||
// Remove mark from whichever container has it
|
// Remove the mark from the given workspace
|
||||||
|
if (workspace_has_mark(ws, mark)) {
|
||||||
|
workspace_find_and_unmark(mark);
|
||||||
|
}
|
||||||
|
} else if (ws && !mark) {
|
||||||
|
// Clear all marks from the given workspace
|
||||||
|
workspace_clear_marks(ws);
|
||||||
|
} else if (!con && !ws && mark) {
|
||||||
|
// Remove mark from whichever container/workspace has it
|
||||||
container_find_and_unmark(mark);
|
container_find_and_unmark(mark);
|
||||||
|
workspace_find_and_unmark(mark);
|
||||||
} else {
|
} else {
|
||||||
// Remove all marks from all containers
|
// Remove all marks from all containers and workspaces
|
||||||
root_for_each_container(remove_all_marks_iterator, NULL);
|
root_for_each_container(remove_all_container_marks_iterator, NULL);
|
||||||
|
root_for_each_workspace(remove_all_workspace_marks_iterator, NULL);
|
||||||
}
|
}
|
||||||
free(mark);
|
free(mark);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -497,27 +497,63 @@ struct match_data {
|
||||||
list_t *matches;
|
list_t *matches;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void criteria_get_containers_iterator(struct sway_container *container,
|
static void criteria_get_nodes_container_iterator(struct sway_container *container,
|
||||||
void *data) {
|
void *data) {
|
||||||
struct match_data *match_data = data;
|
struct match_data *match_data = data;
|
||||||
if (container->view) {
|
if (container->view) {
|
||||||
if (criteria_matches_view(match_data->criteria, container->view)) {
|
if (criteria_matches_view(match_data->criteria, container->view)) {
|
||||||
list_add(match_data->matches, container);
|
list_add(match_data->matches, &container->node);
|
||||||
}
|
}
|
||||||
} else if (has_container_criteria(match_data->criteria)) {
|
} else if (has_container_criteria(match_data->criteria)) {
|
||||||
if (criteria_matches_container(match_data->criteria, container)) {
|
if (criteria_matches_container(match_data->criteria, container)) {
|
||||||
list_add(match_data->matches, container);
|
list_add(match_data->matches, &container->node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list_t *criteria_get_containers(struct criteria *criteria) {
|
static bool criteria_matches_workspace(struct criteria *criteria,
|
||||||
|
struct sway_workspace *workspace) {
|
||||||
|
if (criteria->con_mark) {
|
||||||
|
bool exists = false;
|
||||||
|
for (int i = 0; i < workspace->marks->length; ++i) {
|
||||||
|
if (regex_cmp(workspace->marks->items[i], criteria->con_mark->regex) >= 0) {
|
||||||
|
exists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!exists) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (criteria->con_id) {
|
||||||
|
if (workspace->node.id != criteria->con_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void criteria_get_nodes_workspace_iterator(struct sway_workspace *workspace,
|
||||||
|
void *data) {
|
||||||
|
struct match_data *match_data = data;
|
||||||
|
if (criteria_matches_workspace(match_data->criteria, workspace)) {
|
||||||
|
list_add(match_data->matches, &workspace->node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_t *criteria_get_nodes(struct criteria *criteria) {
|
||||||
list_t *matches = create_list();
|
list_t *matches = create_list();
|
||||||
struct match_data data = {
|
struct match_data data = {
|
||||||
.criteria = criteria,
|
.criteria = criteria,
|
||||||
.matches = matches,
|
.matches = matches,
|
||||||
};
|
};
|
||||||
root_for_each_container(criteria_get_containers_iterator, &data);
|
root_for_each_container(criteria_get_nodes_container_iterator, &data);
|
||||||
|
// Also check workspaces for con_id and con_mark matching
|
||||||
|
if (criteria->con_id || criteria->con_mark) {
|
||||||
|
root_for_each_workspace(criteria_get_nodes_workspace_iterator, &data);
|
||||||
|
}
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -530,6 +530,14 @@ static void ipc_json_describe_workspace(struct sway_workspace *workspace,
|
||||||
json_object_new_string(
|
json_object_new_string(
|
||||||
ipc_json_orientation_description(workspace->layout)));
|
ipc_json_orientation_description(workspace->layout)));
|
||||||
|
|
||||||
|
// Marks
|
||||||
|
json_object *marks = json_object_new_array();
|
||||||
|
for (int i = 0; i < workspace->marks->length; ++i) {
|
||||||
|
json_object_array_add(marks,
|
||||||
|
json_object_new_string(workspace->marks->items[i]));
|
||||||
|
}
|
||||||
|
json_object_object_add(object, "marks", marks);
|
||||||
|
|
||||||
// Floating
|
// Floating
|
||||||
json_object *floating_array = json_object_new_array();
|
json_object *floating_array = json_object_new_array();
|
||||||
for (int i = 0; i < workspace->floating->length; ++i) {
|
for (int i = 0; i < workspace->floating->length; ++i) {
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ struct sway_workspace *workspace_create(struct sway_output *output,
|
||||||
ws->floating = create_list();
|
ws->floating = create_list();
|
||||||
ws->tiling = create_list();
|
ws->tiling = create_list();
|
||||||
ws->output_priority = create_list();
|
ws->output_priority = create_list();
|
||||||
|
ws->marks = create_list();
|
||||||
|
|
||||||
ws->gaps_outer = config->gaps_outer;
|
ws->gaps_outer = config->gaps_outer;
|
||||||
ws->gaps_inner = config->gaps_inner;
|
ws->gaps_inner = config->gaps_inner;
|
||||||
|
|
@ -151,6 +152,7 @@ void workspace_destroy(struct sway_workspace *workspace) {
|
||||||
free(workspace->name);
|
free(workspace->name);
|
||||||
free(workspace->representation);
|
free(workspace->representation);
|
||||||
list_free_items_and_destroy(workspace->output_priority);
|
list_free_items_and_destroy(workspace->output_priority);
|
||||||
|
list_free_items_and_destroy(workspace->marks);
|
||||||
list_free(workspace->floating);
|
list_free(workspace->floating);
|
||||||
list_free(workspace->tiling);
|
list_free(workspace->tiling);
|
||||||
list_free(workspace->current.floating);
|
list_free(workspace->current.floating);
|
||||||
|
|
@ -985,3 +987,54 @@ void workspace_squash(struct sway_workspace *workspace) {
|
||||||
i += container_squash(child);
|
i += container_squash(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool workspace_has_mark(struct sway_workspace *ws, char *mark) {
|
||||||
|
for (int i = 0; i < ws->marks->length; ++i) {
|
||||||
|
char *item = ws->marks->items[i];
|
||||||
|
if (strcmp(item, mark) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void workspace_add_mark(struct sway_workspace *ws, char *mark) {
|
||||||
|
list_add(ws->marks, strdup(mark));
|
||||||
|
ipc_event_workspace(NULL, ws, "mark");
|
||||||
|
}
|
||||||
|
|
||||||
|
void workspace_clear_marks(struct sway_workspace *ws) {
|
||||||
|
for (int i = 0; i < ws->marks->length; ++i) {
|
||||||
|
free(ws->marks->items[i]);
|
||||||
|
}
|
||||||
|
ws->marks->length = 0;
|
||||||
|
ipc_event_workspace(NULL, ws, "mark");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool find_by_mark_iterator_ws(struct sway_workspace *ws, void *data) {
|
||||||
|
char *mark = data;
|
||||||
|
return workspace_has_mark(ws, mark);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_workspace *workspace_find_mark(char *mark) {
|
||||||
|
return root_find_workspace(find_by_mark_iterator_ws, mark);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool workspace_find_and_unmark(char *mark) {
|
||||||
|
struct sway_workspace *ws = root_find_workspace(
|
||||||
|
find_by_mark_iterator_ws, mark);
|
||||||
|
if (!ws) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < ws->marks->length; ++i) {
|
||||||
|
char *ws_mark = ws->marks->items[i];
|
||||||
|
if (strcmp(ws_mark, mark) == 0) {
|
||||||
|
free(ws_mark);
|
||||||
|
list_del(ws->marks, i);
|
||||||
|
ipc_event_workspace(NULL, ws, "mark");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue