diff options
Diffstat (limited to 'sway/tree/workspace.c')
-rw-r--r-- | sway/tree/workspace.c | 107 |
1 files changed, 100 insertions, 7 deletions
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index ba04c55c..5800ea09 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -1,8 +1,11 @@ | |||
1 | #define _XOPEN_SOURCE 500 | 1 | #define _XOPEN_SOURCE 500 |
2 | #include <ctype.h> | ||
3 | #include <limits.h> | ||
2 | #include <stdbool.h> | 4 | #include <stdbool.h> |
3 | #include <stdlib.h> | 5 | #include <stdlib.h> |
4 | #include <stdio.h> | 6 | #include <stdio.h> |
5 | #include <strings.h> | 7 | #include <strings.h> |
8 | #include "stringop.h" | ||
6 | #include "sway/tree/container.h" | 9 | #include "sway/tree/container.h" |
7 | #include "sway/input/input-manager.h" | 10 | #include "sway/input/input-manager.h" |
8 | #include "sway/input/seat.h" | 11 | #include "sway/input/seat.h" |
@@ -22,18 +25,108 @@ void next_name_map(struct sway_container *ws, void *data) { | |||
22 | ++count; | 25 | ++count; |
23 | } | 26 | } |
24 | 27 | ||
28 | static bool workspace_valid_on_output(const char *output_name, | ||
29 | const char *ws_name) { | ||
30 | int i; | ||
31 | for (i = 0; i < config->workspace_outputs->length; ++i) { | ||
32 | struct workspace_output *wso = config->workspace_outputs->items[i]; | ||
33 | if (strcasecmp(wso->workspace, ws_name) == 0) { | ||
34 | if (strcasecmp(wso->output, output_name) != 0) { | ||
35 | return false; | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | return true; | ||
41 | } | ||
42 | |||
25 | char *workspace_next_name(const char *output_name) { | 43 | char *workspace_next_name(const char *output_name) { |
26 | wlr_log(L_DEBUG, "Workspace: Generating new workspace name for output %s", | 44 | wlr_log(L_DEBUG, "Workspace: Generating new workspace name for output %s", |
27 | output_name); | 45 | output_name); |
28 | int count = 0; | 46 | int l = 1; |
29 | next_name_map(&root_container, &count); | 47 | // Scan all workspace bindings to find the next available workspace name, |
30 | ++count; | 48 | // if none are found/available then default to a number |
31 | int len = snprintf(NULL, 0, "%d", count); | 49 | struct sway_mode *mode = config->current_mode; |
32 | char *name = malloc(len + 1); | 50 | |
33 | if (!sway_assert(name, "Failed to allocate workspace name")) { | 51 | // TODO: iterate over keycode bindings too |
52 | int order = INT_MAX; | ||
53 | char *target = NULL; | ||
54 | for (int i = 0; i < mode->keysym_bindings->length; ++i) { | ||
55 | struct sway_binding *binding = mode->keysym_bindings->items[i]; | ||
56 | char *cmdlist = strdup(binding->command); | ||
57 | char *dup = cmdlist; | ||
58 | char *name = NULL; | ||
59 | |||
60 | // workspace n | ||
61 | char *cmd = argsep(&cmdlist, " "); | ||
62 | if (cmdlist) { | ||
63 | name = argsep(&cmdlist, ",;"); | ||
64 | } | ||
65 | |||
66 | if (strcmp("workspace", cmd) == 0 && name) { | ||
67 | wlr_log(L_DEBUG, "Got valid workspace command for target: '%s'", name); | ||
68 | char *_target = strdup(name); | ||
69 | strip_quotes(_target); | ||
70 | while (isspace(*_target)) { | ||
71 | memmove(_target, _target+1, strlen(_target+1)); | ||
72 | } | ||
73 | |||
74 | // Make sure that the command references an actual workspace | ||
75 | // not a command about workspaces | ||
76 | if (strcmp(_target, "next") == 0 || | ||
77 | strcmp(_target, "prev") == 0 || | ||
78 | strcmp(_target, "next_on_output") == 0 || | ||
79 | strcmp(_target, "prev_on_output") == 0 || | ||
80 | strcmp(_target, "number") == 0 || | ||
81 | strcmp(_target, "back_and_forth") == 0 || | ||
82 | strcmp(_target, "current") == 0) | ||
83 | { | ||
84 | free(_target); | ||
85 | free(dup); | ||
86 | continue; | ||
87 | } | ||
88 | |||
89 | // Make sure that the workspace doesn't already exist | ||
90 | if (workspace_by_name(_target)) { | ||
91 | free(_target); | ||
92 | free(dup); | ||
93 | continue; | ||
94 | } | ||
95 | |||
96 | // make sure that the workspace can appear on the given | ||
97 | // output | ||
98 | if (!workspace_valid_on_output(output_name, _target)) { | ||
99 | free(_target); | ||
100 | free(dup); | ||
101 | continue; | ||
102 | } | ||
103 | |||
104 | if (binding->order < order) { | ||
105 | order = binding->order; | ||
106 | free(target); | ||
107 | target = _target; | ||
108 | wlr_log(L_DEBUG, "Workspace: Found free name %s", _target); | ||
109 | } | ||
110 | } | ||
111 | free(dup); | ||
112 | } | ||
113 | if (target != NULL) { | ||
114 | return target; | ||
115 | } | ||
116 | // As a fall back, get the current number of active workspaces | ||
117 | // and return that + 1 for the next workspace's name | ||
118 | int ws_num = root_container.children->length; | ||
119 | if (ws_num >= 10) { | ||
120 | l = 2; | ||
121 | } else if (ws_num >= 100) { | ||
122 | l = 3; | ||
123 | } | ||
124 | char *name = malloc(l + 1); | ||
125 | if (!name) { | ||
126 | wlr_log(L_ERROR, "Could not allocate workspace name"); | ||
34 | return NULL; | 127 | return NULL; |
35 | } | 128 | } |
36 | snprintf(name, len + 1, "%d", count); | 129 | sprintf(name, "%d", ws_num++); |
37 | return name; | 130 | return name; |
38 | } | 131 | } |
39 | 132 | ||