aboutsummaryrefslogtreecommitdiffstats
path: root/sway/workspace.c
blob: 7b23b7d146b5a02a8ca08327a58d14d5b0a5d620 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <stdlib.h>
#include <stdbool.h>
#include <wlc/wlc.h>
#include "workspace.h"
#include "layout.h"
#include "list.h"
#include "log.h"
#include "container.h"
#include "config.h"
#include "stringop.h"

swayc_t *active_workspace = NULL;

char *workspace_next_name(void) {
	sway_log(L_DEBUG, "Workspace: Generating new name");
	int i;
	int l = 1;
	// 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;

	for (i = 0; i < mode->bindings->length; ++i) {
		struct sway_binding *binding = mode->bindings->items[i];
		const char* command = binding->command;
		list_t *args = split_string(command, " ");

		if (strcmp("workspace", args->items[0]) == 0 && args->length > 1) {
			sway_log(L_DEBUG, "Got valid workspace command for target: '%s'", args->items[1]);
			const char* target = args->items[1];

			while (*target == ' ' || *target == '\t')
				target++; 

			// 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)
				continue;
		   
			//Make sure that the workspace doesn't already exist 
			if (workspace_find_by_name(args->items[1]))
			   continue; 

			list_free(args);

			sway_log(L_DEBUG, "Workspace: Found free name %s", args->items[1]);
			return args->items[1];
		}
	}
	// As a fall back, get the current number of active workspaces
	// and return that + 1 for the next workspace's name
	int ws_num = root_container.children->length;
	if (ws_num >= 10) {
		l = 2;
	} else if (ws_num >= 100) {
		l = 3;
	}
	char *name = malloc(l + 1);
	sprintf(name, "%d", ws_num++);
	return name;
}

swayc_t *workspace_create(const char* name) {
	swayc_t *parent = get_focused_container(&root_container);
	while(parent->type != C_OUTPUT) {
		parent = parent->parent;
	}

	swayc_t *workspace = create_container(parent, -1);
	workspace->type = C_WORKSPACE;
	workspace->name = strdup(name);
	workspace->width = parent->width;
	workspace->height = parent->height;
	workspace->layout = L_HORIZ; // todo: thing
	
	add_child(parent, workspace);
	return workspace;
}

bool workspace_by_name(swayc_t *view, void *data) {
	return (view->type == C_WORKSPACE) && 
		   (strcasecmp(view->name, (char *) data) == 0);
}

bool workspace_destroy(swayc_t *workspace) {
	//Dont destroy if there are children
	if (workspace->children->length) {
		return false;
	}
	sway_log(L_DEBUG, "Workspace: Destroying workspace '%s'", workspace->name);
	free_swayc(workspace);
	return true;
}

void set_mask(swayc_t *view, void *data) {
	uint32_t *p = data;

	if(view->type == C_VIEW) {
		wlc_view_set_mask(view->handle, *p);
		view->visible = (*p == 2);
	}
}

swayc_t *workspace_find_by_name(const char* name) {
	return find_container(&root_container, workspace_by_name, (void *) name);
}

void workspace_switch(swayc_t *workspace) {
	if (workspace != active_workspace && active_workspace) {
		sway_log(L_DEBUG, "workspace: changing from '%s' to '%s'", active_workspace->name, workspace->name);
		uint32_t mask = 1;
		// set all c_views in the old workspace to the invisible mask
		container_map(active_workspace, set_mask, &mask);

		// and c_views in the new workspace to the visible mask
		mask = 2;
		container_map(workspace, set_mask, &mask);

		wlc_output_set_mask(wlc_get_focused_output(), 2);
		unfocus_all(active_workspace);
		focus_view(workspace);
		workspace_destroy(active_workspace);
	}
	active_workspace = workspace;
}