Exemplo n.º 1
0
void move_container_to(swayc_t* container, swayc_t* destination) {
	if (container == destination || swayc_is_parent_of(container, destination)) {
		return;
	}
	swayc_t *parent = remove_child(container);
	// reset container geometry
	container->width = container->height = 0;

	// Send to new destination
	if (container->is_floating) {
		add_floating(swayc_active_workspace_for(destination), container);
	} else if (destination->type == C_WORKSPACE) {
		add_child(destination, container);
	} else {
		add_sibling(destination, container);
	}
	// Destroy old container if we need to
	parent = destroy_container(parent);
	// Refocus
	swayc_t *op1 = swayc_parent_by_type(destination, C_OUTPUT);
	swayc_t *op2 = swayc_parent_by_type(parent, C_OUTPUT);
	set_focused_container(get_focused_view(op1));
	arrange_windows(op1, -1, -1);
	update_visibility(op1);
	if (op1 != op2) {
		set_focused_container(get_focused_view(op2));
		arrange_windows(op2, -1, -1);
		update_visibility(op2);
	}
}
Exemplo n.º 2
0
bool workspace_switch(swayc_t *workspace) {
	if (!workspace) {
		return false;
	}
	swayc_t *active_ws = swayc_active_workspace();
	if (config->auto_back_and_forth && active_ws == workspace && prev_workspace_name) {
		swayc_t *new_ws = workspace_by_name(prev_workspace_name);
		workspace = new_ws ? new_ws : workspace_create(prev_workspace_name);
	}

	if (!prev_workspace_name
			|| (strcmp(prev_workspace_name, active_ws->name)
				&& active_ws != workspace)) {
		free(prev_workspace_name);
		prev_workspace_name = malloc(strlen(active_ws->name)+1);
		strcpy(prev_workspace_name, active_ws->name);
	}

	// move sticky containers
	if (swayc_parent_by_type(active_ws, C_OUTPUT) == swayc_parent_by_type(workspace, C_OUTPUT)) {
		// don't change list while traversing it, use intermediate list instead
		list_t *stickies = create_list();
		for (int i = 0; i < active_ws->floating->length; i++) {
			swayc_t *cont = active_ws->floating->items[i];
			if (cont->sticky) {
				list_add(stickies, cont);
			}
		}
		for (int i = 0; i < stickies->length; i++) {
			swayc_t *cont = stickies->items[i];
			sway_log(L_DEBUG, "Moving sticky container %p to %p:%s",
					cont, workspace, workspace->name);
			swayc_t *parent = remove_child(cont);
			add_floating(workspace, cont);
			// Destroy old container if we need to
			destroy_container(parent);
		}
		list_free(stickies);
	}
	sway_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name);
	if (!set_focused_container(get_focused_view(workspace))) {
		return false;
	}
	swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
	arrange_backgrounds();
	arrange_windows(output, -1, -1);
	return true;
}
Exemplo n.º 3
0
Arquivo: layout.c Projeto: thuck/sway
static void update_border_geometry_floating(swayc_t *c, struct wlc_geometry *geometry) {
	struct wlc_geometry g = *geometry;
	c->actual_geometry = g;

	swayc_t *output = swayc_parent_by_type(c, C_OUTPUT);
	const struct wlc_size *res = wlc_output_get_resolution(output->handle);

	switch (c->border_type) {
	case B_NONE:
		break;
	case B_PIXEL:
		adjust_border_geometry(c, &g, res, c->border_thickness,
			c->border_thickness, c->border_thickness, c->border_thickness);
		break;
	case B_NORMAL:
	{
		int title_bar_height = config->font_height + 4; // borders + padding

		adjust_border_geometry(c, &g, res, c->border_thickness,
			c->border_thickness, title_bar_height, c->border_thickness);

		struct wlc_geometry title_bar = {
			.origin = {
				.x = c->actual_geometry.origin.x - c->border_thickness,
				.y = c->actual_geometry.origin.y - title_bar_height
			},
			.size = {
				.w = c->actual_geometry.size.w + (2 * c->border_thickness),
				.h = title_bar_height
			}
		};
		c->title_bar_geometry = title_bar;
		break;
	}
	}
Exemplo n.º 4
0
bool move_focus(enum movement_direction direction) {
	swayc_t *old_view = get_focused_container(&root_container);
	swayc_t *new_view = get_swayc_in_direction(old_view, direction);
	if (!new_view) {
		return false;
	} else if (new_view->type == C_ROOT) {
		sway_log(L_DEBUG, "Not setting focus above the workspace level");
		return false;
	} else if (new_view->type == C_OUTPUT) {
		return set_focused_container(swayc_active_workspace_for(new_view));
	} else if (direction == MOVE_PARENT || direction == MOVE_CHILD) {
		return set_focused_container(new_view);
	} else if (config->mouse_warping) {
		swayc_t *old_op = old_view->type == C_OUTPUT ?
			old_view : swayc_parent_by_type(old_view, C_OUTPUT);
		swayc_t *focused = get_focused_view(new_view);
		if (set_focused_container(focused)) {
			if (old_op != swayc_active_output() && focused && focused->type == C_VIEW) {
				center_pointer_on(focused);
			}
			return true;
		}
	} else {
		return set_focused_container(get_focused_view(new_view));
	}
	return false;
}
Exemplo n.º 5
0
static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) {
	swayc_t *c = get_swayc_for_handle(view, &root_container);
	switch (state) {
	case WLC_BIT_FULLSCREEN:
		// i3 just lets it become fullscreen
		wlc_view_set_state(view, state, toggle);
		if (c) {
			sway_log(L_DEBUG, "setting view %ld %s, fullscreen %d", view, c->name, toggle);
			arrange_windows(c->parent, -1, -1);
			// Set it as focused window for that workspace if its going fullscreen
			if (toggle) {
				swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE);
				// Set ws focus to c
				set_focused_container_for(ws, c);
			}
		}
		break;
	case WLC_BIT_MAXIMIZED:
	case WLC_BIT_RESIZING:
	case WLC_BIT_MOVING:
		break;
	case WLC_BIT_ACTIVATED:
		sway_log(L_DEBUG, "View %p requested to be activated", c);
		break;
	}
	return;
}
Exemplo n.º 6
0
Arquivo: layout.c Projeto: thuck/sway
void move_container_to(swayc_t* container, swayc_t* destination) {
	if (container == destination || swayc_is_parent_of(container, destination)) {
		return;
	}
	swayc_t *parent = remove_child(container);
	// Send to new destination
	if (container->is_floating) {
		swayc_t *ws = swayc_active_workspace_for(destination);
		add_floating(ws, container);

		// If the workspace only has one child after adding one, it
		// means that the workspace was just initialized.
		if (ws->children->length + ws->floating->length == 1) {
			ipc_event_workspace(NULL, ws, "init");
		}
	} else if (destination->type == C_WORKSPACE) {
		// reset container geometry
		container->width = container->height = 0;
		add_child(destination, container);

		// If the workspace only has one child after adding one, it
		// means that the workspace was just initialized.
		if (destination->children->length + destination->floating->length == 1) {
			ipc_event_workspace(NULL, destination, "init");
		}
	} else {
		// reset container geometry
		container->width = container->height = 0;
		add_sibling(destination, container);
	}
	// Destroy old container if we need to
	parent = destroy_container(parent);
	// Refocus
	swayc_t *op1 = swayc_parent_by_type(destination, C_OUTPUT);
	swayc_t *op2 = swayc_parent_by_type(parent, C_OUTPUT);
	set_focused_container(get_focused_view(op1));
	arrange_windows(op1, -1, -1);
	update_visibility(op1);
	if (op1 != op2) {
		set_focused_container(get_focused_view(op2));
		arrange_windows(op2, -1, -1);
		update_visibility(op2);
	}
}
Exemplo n.º 7
0
static bool pointer_test(swayc_t *view, void *_origin) {
	const struct wlc_origin *origin = _origin;
	// Determine the output that the view is under
	swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
	if (origin->x >= view->x && origin->y >= view->y
		&& origin->x < view->x + view->width && origin->y < view->y + view->height
		&& view->visible && parent == root_container.focused) {
		return true;
	}
	return false;
}
Exemplo n.º 8
0
static void ipc_json_describe_view(swayc_t *c, json_object *object) {
	json_object *props = json_object_new_object();
	float percent = ipc_json_child_percentage(c);
	const char *layout = (c->parent->type == C_CONTAINER) ?
		ipc_json_layout_description(c->parent->layout) : "none";
	const char *last_layout = (c->parent->type == C_CONTAINER) ?
		ipc_json_layout_description(c->parent->prev_layout) : "none";
	wlc_handle parent = wlc_view_get_parent(c->handle);

	json_object_object_add(object, "type", json_object_new_string((c->is_floating) ? "floating_con" : "con"));

	json_object_object_add(object, "scratchpad_state",
		json_object_new_string(ipc_json_get_scratchpad_state(c)));
	json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL);
	// TODO: make urgency actually work once Sway supports it
	json_object_object_add(object, "urgent", json_object_new_boolean(false));
	json_object_object_add(object, "layout",
		(strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout));
	json_object_object_add(object, "last_split_layout",
		(strcmp(last_layout, "null") == 0) ? NULL : json_object_new_string(last_layout));
	json_object_object_add(object, "workspace_layout",
		json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->workspace_layout)));

	json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c)));
	json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness));

	json_object_object_add(object, "rect", ipc_json_create_rect(c));
	json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry));
	json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry));
	json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry));

	json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL);

	json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat
	json_object_object_add(props, "class", c->class ? json_object_new_string(c->class) :
		c->app_id ? json_object_new_string(c->app_id) : NULL);
	json_object_object_add(props, "instance", c->instance ? json_object_new_string(c->instance) :
		c->app_id ? json_object_new_string(c->app_id) : NULL);
	json_object_object_add(props, "title", (c->name) ? json_object_new_string(c->name) : NULL);
	json_object_object_add(props, "transient_for", parent ? json_object_new_int(parent) : NULL);
	json_object_object_add(object, "window_properties", props);

	json_object_object_add(object, "fullscreen_mode",
		json_object_new_int(swayc_is_fullscreen(c) ? 1 : 0));
	json_object_object_add(object, "sticky", json_object_new_boolean(c->sticky));
	json_object_object_add(object, "floating", json_object_new_string(
		c->is_floating ? "auto_on" : "auto_off")); // we can't state the cause

	json_object_object_add(object, "app_id", c->app_id ? json_object_new_string(c->app_id) : NULL);
}
Exemplo n.º 9
0
swayc_t *destroy_workspace(swayc_t *workspace) {
	if (!ASSERT_NONNULL(workspace)) {
		return NULL;
	}
	// NOTE: This is called from elsewhere without checking children length
	// TODO move containers to other workspaces?
	// for now just dont delete
	
	// Do not destroy this if it's the last workspace on this output
	swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT);
	if (output && output->children->length == 1) {
		return NULL;
	}

	if (workspace->children->length == 0) {
		sway_log(L_DEBUG, "%s: '%s'", __func__, workspace->name);
		swayc_t *parent = workspace->parent;
		free_swayc(workspace);
		return parent;
	}
	return NULL;
}
Exemplo n.º 10
0
bool move_focus(enum movement_direction direction) {
	swayc_t *old_view = get_focused_container(&root_container);
	swayc_t *new_view = get_swayc_in_direction(old_view, direction);
	if (!new_view) {
		return false;
	} else if (direction == MOVE_PARENT) {
		return set_focused_container(new_view);
	} else if (config->mouse_warping) {
		swayc_t *old_op = old_view->type == C_OUTPUT ?
			old_view : swayc_parent_by_type(old_view, C_OUTPUT);
		swayc_t *focused = get_focused_view(new_view);
		if (set_focused_container(focused)) {
			if (old_op != swayc_active_output() && focused && focused->type == C_VIEW) {
				center_pointer_on(focused);
			}
			return true;
		}
	} else {
		return set_focused_container(get_focused_view(new_view));
	}
	return false;
}
Exemplo n.º 11
0
void update_geometry(swayc_t *container) {
	if (container->type != C_VIEW) {
		return;
	}
	swayc_t *ws = swayc_parent_by_type(container, C_WORKSPACE);
	swayc_t *op = ws->parent;
	int gap = container->is_floating ? 0 : swayc_gap(container);
	if (gap % 2 != 0) {
		// because gaps are implemented as "half sized margins" it's currently
		// not possible to align views properly with odd sized gaps.
		gap -= 1;
	}

	struct wlc_geometry geometry = {
		.origin = {
			.x = container->x + gap/2 < op->width  ? container->x + gap/2 : op->width-1,
			.y = container->y + gap/2 < op->height ? container->y + gap/2 : op->height-1
		},
		.size = {
			.w = container->width > gap ? container->width - gap : 1,
			.h = container->height > gap ? container->height - gap : 1,
		}
	};
Exemplo n.º 12
0
struct cmd_results *cmd_fullscreen(int argc, char **argv) {
	struct cmd_results *error = NULL;
	if (config->reading) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can't be used in config file.");
	if (!config->active) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can only be used when sway is running.");
	if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0))) {
		return error;
	}
	swayc_t *container = get_focused_view(&root_container);
	if(container->type != C_VIEW){
		return cmd_results_new(CMD_INVALID, "fullscreen", "Only views can fullscreen");
	}
	swayc_t *workspace = swayc_parent_by_type(container, C_WORKSPACE);
	bool current = swayc_is_fullscreen(container);
	wlc_view_set_state(container->handle, WLC_BIT_FULLSCREEN, !current);

	if (container->is_floating) {
		if (current) {
			// set dimensions back to what they were before we fullscreened this
			container->x = container->cached_geometry.origin.x;
			container->y = container->cached_geometry.origin.y;
			container->width = container->cached_geometry.size.w;
			container->height = container->cached_geometry.size.h;
		} else {
			// cache dimensions so we can reset them after we "unfullscreen" this
			struct wlc_geometry geo = {
				.origin = {
					.x = container->x,
					.y = container->y
				},
				.size = {
					.w = container->width,
					.h = container->height
				}
			};
			container->cached_geometry = geo;
		}
	}
Exemplo n.º 13
0
swayc_t *workspace_create(const char* name) {
	swayc_t *parent;
	// Search for workspace<->output pair
	int i, e = config->workspace_outputs->length;
	for (i = 0; i < e; ++i) {
		struct workspace_output *wso = config->workspace_outputs->items[i];
		if (strcasecmp(wso->workspace, name) == 0)
		{
			// Find output to use if it exists
			e = root_container.children->length;
			for (i = 0; i < e; ++i) {
				parent = root_container.children->items[i];
				if (strcmp(parent->name, wso->output) == 0) {
					return new_workspace(parent, name);
				}
			}
			break;
		}
	}
	// Otherwise create a new one
	parent = get_focused_container(&root_container);
	parent = swayc_parent_by_type(parent, C_OUTPUT);
	return new_workspace(parent, name);
}
Exemplo n.º 14
0
Arquivo: layout.c Projeto: FSMaxB/sway
void arrange_windows(swayc_t *container, int width, int height) {
	int i;
	if (width == -1 || height == -1) {
		sway_log(L_DEBUG, "Arranging layout for %p", container);
		width = container->width;
		height = container->height;
	}

	int x = 0, y = 0;
	switch (container->type) {
	case C_ROOT:
		for (i = 0; i < container->children->length; ++i) {
			swayc_t *child = container->children->items[i];
			sway_log(L_DEBUG, "Arranging output at %d", x);
			child->x = x;
			child->y = y;
			arrange_windows(child, -1, -1);
			// Removed for now because wlc works with relative positions
			// Addition can be reconsidered once wlc positions are changed
			// x += child->width;
		}
		return;
	case C_OUTPUT:
		container->width = width;
		container->height = height;
		// These lines make x/y negative and result in stuff glitching out
		// Their addition can be reconsidered once wlc positions are changed
		// x -= container->x;
		// y -= container->y;
		for (i = 0; i < container->children->length; ++i) {
			swayc_t *child = container->children->items[i];
			child->x = x + container->gaps;
			child->y = y + container->gaps;
			child->width = width - container->gaps * 2;
			child->height = height - container->gaps * 2;
			sway_log(L_DEBUG, "Arranging workspace #%d at %d, %d", i, child->x, child->y);
			arrange_windows(child, -1, -1);
		}
		return;
	case C_VIEW:
		{
			struct wlc_geometry geometry = {
				.origin = {
					.x = container->x + container->gaps / 2,
					.y = container->y + container->gaps / 2
				},
				.size = {
					.w = width - container->gaps,
					.h = height - container->gaps
				}
			};
			if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) {
				swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT);
				geometry.origin.x = 0;
				geometry.origin.y = 0;
				geometry.size.w = parent->width;
				geometry.size.h = parent->height;
				wlc_view_set_geometry(container->handle, 0, &geometry);
				wlc_view_bring_to_front(container->handle);
			} else {
				wlc_view_set_geometry(container->handle, 0, &geometry);
				container->width = width;
				container->height = height;
			}
			sway_log(L_DEBUG, "Set view to %d x %d @ %d, %d", geometry.size.w, geometry.size.h,
					geometry.origin.x, geometry.origin.y);
		}
		return;
	default:
		container->width = width;
		container->height = height;
		break;
	}
Exemplo n.º 15
0
static bool handle_view_created(wlc_handle handle) {
	// if view is child of another view, the use that as focused container
	wlc_handle parent = wlc_view_get_parent(handle);
	swayc_t *focused = NULL;
	swayc_t *newview = NULL;

	// Get parent container, to add view in
	if (parent) {
		focused = get_swayc_for_handle(parent, &root_container);
	}
	if (!focused || focused->type == C_OUTPUT) {
		focused = get_focused_container(&root_container);
	}
	sway_log(L_DEBUG, "handle:%ld type:%x state:%x parent:%ld "
			"mask:%d (x:%d y:%d w:%d h:%d) title:%s "
			"class:%s appid:%s",
		handle, wlc_view_get_type(handle), wlc_view_get_state(handle), parent,
		wlc_view_get_mask(handle), wlc_view_get_geometry(handle)->origin.x,
		wlc_view_get_geometry(handle)->origin.y,wlc_view_get_geometry(handle)->size.w,
		wlc_view_get_geometry(handle)->size.h, wlc_view_get_title(handle),
		wlc_view_get_class(handle), wlc_view_get_app_id(handle));

	// TODO properly figure out how each window should be handled.
	switch (wlc_view_get_type(handle)) {
	// regular view created regularly
	case 0:
		newview = new_view(focused, handle);
		wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true);
		break;

	// Dmenu keeps viewfocus, but others with this flag dont, for now simulate
	// dmenu
	case WLC_BIT_OVERRIDE_REDIRECT:
// 		locked_view_focus = true;
		wlc_view_focus(handle);
		wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true);
		wlc_view_bring_to_front(handle);
		break;

	// Firefox popups have this flag set.
	case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED:
		wlc_view_bring_to_front(handle);
		locked_container_focus = true;
		break;

	// Modals, get focus, popups do not
	case WLC_BIT_MODAL:
		wlc_view_focus(handle);
		wlc_view_bring_to_front(handle);
		newview = new_floating_view(handle);
	case WLC_BIT_POPUP:
		wlc_view_bring_to_front(handle);
		break;
	}

	if (newview) {
		set_focused_container(newview);
		swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT);
		arrange_windows(output, -1, -1);
	}
	return true;
}
Exemplo n.º 16
0
struct cmd_results *cmd_layout(int argc, char **argv) {
	struct cmd_results *error = NULL;
	if (config->reading) return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file.");
	if (!config->active) return cmd_results_new(CMD_FAILURE, "layout", "Can only be used when sway is running.");
	if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) {
		return error;
	}
	swayc_t *parent = get_focused_container(&root_container);
	if (parent->is_floating) {
		return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows");
	}

	while (parent->type == C_VIEW) {
		parent = parent->parent;
	}

	enum swayc_layouts old_layout = parent->layout;

	if (strcasecmp(argv[0], "default") == 0) {
		swayc_change_layout(parent, parent->prev_layout);
		if (parent->layout == L_NONE) {
			swayc_t *output = swayc_parent_by_type(parent, C_OUTPUT);
			swayc_change_layout(parent, default_layout(output));
		}
	} else {
		if (parent->layout != L_TABBED && parent->layout != L_STACKED) {
			parent->prev_layout = parent->layout;
		}

		if (strcasecmp(argv[0], "tabbed") == 0) {
			if (parent->type != C_CONTAINER && !swayc_is_empty_workspace(parent)){
				parent = new_container(parent, L_TABBED);
			}

			swayc_change_layout(parent, L_TABBED);
		} else if (strcasecmp(argv[0], "stacking") == 0) {
			if (parent->type != C_CONTAINER && !swayc_is_empty_workspace(parent)) {
				parent = new_container(parent, L_STACKED);
			}

			swayc_change_layout(parent, L_STACKED);
		} else if (strcasecmp(argv[0], "splith") == 0) {
			swayc_change_layout(parent, L_HORIZ);
		} else if (strcasecmp(argv[0], "splitv") == 0) {
			swayc_change_layout(parent, L_VERT);
		} else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
			if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE || parent->workspace_layout == L_HORIZ)) {
				swayc_change_layout(parent, L_VERT);
			} else {
				swayc_change_layout(parent, L_HORIZ);
			}
		}
	}

	update_layout_geometry(parent, old_layout);
	update_geometry(parent);

	arrange_windows(parent, parent->width, parent->height);

	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
Exemplo n.º 17
0
swayc_t *workspace_create(const char* name) {
	swayc_t *parent = get_focused_container(&root_container);
	parent = swayc_parent_by_type(parent, C_OUTPUT);
	return new_workspace(parent, name);
}