Merge pull request #129 from minus7/workspaces

Implemented "move container to workspace"
This commit is contained in:
Drew DeVault 2015-08-25 16:12:37 -04:00
commit fa6292ff24
12 changed files with 173 additions and 93 deletions

View file

@ -56,6 +56,10 @@ struct sway_container {
struct sway_container *focused; struct sway_container *focused;
}; };
enum visibility_mask {
VISIBLE = 1
};
// Container Creation // Container Creation
swayc_t *new_output(wlc_handle handle); swayc_t *new_output(wlc_handle handle);
@ -106,4 +110,7 @@ void container_map(swayc_t *, void (*f)(swayc_t *, void *), void *);
void set_view_visibility(swayc_t *view, void *data); void set_view_visibility(swayc_t *view, void *data);
void reset_gaps(swayc_t *view, void *data); void reset_gaps(swayc_t *view, void *data);
void update_visibility(swayc_t *container);
#endif #endif

View file

@ -22,6 +22,7 @@ swayc_t *remove_child(swayc_t *child);
void swap_container(swayc_t *a, swayc_t *b); void swap_container(swayc_t *a, swayc_t *b);
void move_container(swayc_t* container,swayc_t* root,enum movement_direction direction); void move_container(swayc_t* container,swayc_t* root,enum movement_direction direction);
void move_container_to(swayc_t* container, swayc_t* destination);
// Layout // Layout
void update_geometry(swayc_t *view); void update_geometry(swayc_t *view);

9
include/util.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef _SWAY_UTIL_H
#define _SWAY_UTIL_H
/**
* Wrap i into the range [0, max[
*/
int wrap(int i, int max);
#endif

View file

@ -9,9 +9,9 @@ char *workspace_next_name(void);
swayc_t *workspace_create(const char*); swayc_t *workspace_create(const char*);
swayc_t *workspace_by_name(const char*); swayc_t *workspace_by_name(const char*);
void workspace_switch(swayc_t*); void workspace_switch(swayc_t*);
void workspace_output_next(); swayc_t *workspace_output_next();
void workspace_next(); swayc_t *workspace_next();
void workspace_output_prev(); swayc_t *workspace_output_prev();
void workspace_prev(); swayc_t *workspace_prev();
#endif #endif

View file

@ -80,6 +80,10 @@ Commands
**move** <left|right|up|down>:: **move** <left|right|up|down>::
Moves the focused container _left_, _right_, _up_, or _down_. Moves the focused container _left_, _right_, _up_, or _down_.
**move** <container|window> to workspace <name>::
Moves the focused container to the workspace identified by _name_.
_name_ may be a special workspace name. See **workspace**.
**output** <name> <resolution|res WIDTHxHEIGHT> <position|pos X,Y>:: **output** <name> <resolution|res WIDTHxHEIGHT> <position|pos X,Y>::
Configures the specified output. It will use the given resolution and be Configures the specified output. It will use the given resolution and be
arranged at the given position in the layout tree. You may omit either of arranged at the given position in the layout tree. You may omit either of
@ -111,6 +115,10 @@ Commands
**workspace** <name>:: **workspace** <name>::
Switches to the specified workspace. Switches to the specified workspace.
**workspace** <prev|next>::
Switches to the next workspace on the current output or on the next output
if currently on the last workspace.
**workspace** <prev_on_output|next_on_output>:: **workspace** <prev_on_output|next_on_output>::
Switches to the next workspace on the current output. Switches to the next workspace on the current output.

View file

@ -344,7 +344,7 @@ static bool cmd_focus_follows_mouse(struct sway_config *config, int argc, char *
} }
static bool cmd_move(struct sway_config *config, int argc, char **argv) { static bool cmd_move(struct sway_config *config, int argc, char **argv) {
if (!checkarg(argc, "workspace", EXPECTED_EQUAL_TO, 1)) { if (!checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1)) {
return false; return false;
} }
@ -358,6 +358,29 @@ static bool cmd_move(struct sway_config *config, int argc, char **argv) {
move_container(view,&root_container,MOVE_UP); move_container(view,&root_container,MOVE_UP);
} else if (strcasecmp(argv[0], "down") == 0) { } else if (strcasecmp(argv[0], "down") == 0) {
move_container(view,&root_container,MOVE_DOWN); move_container(view,&root_container,MOVE_DOWN);
} else if (strcasecmp(argv[0], "container") == 0 || strcasecmp(argv[0], "window") == 0) {
// "move container to workspace x"
if (!checkarg(argc, "move container/window", EXPECTED_EQUAL_TO, 4) ||
strcasecmp(argv[1], "to") != 0 ||
strcasecmp(argv[2], "workspace") != 0) {
return false;
}
if (view->type != C_CONTAINER && view->type != C_VIEW) {
return false;
}
const char *ws_name = argv[3];
if (argc == 5) {
// move "container to workspace number x"
ws_name = argv[4];
}
swayc_t *ws = workspace_by_name(ws_name);
if (ws == NULL) {
ws = workspace_create(ws_name);
}
move_container_to(view, ws);
} else { } else {
return false; return false;
} }
@ -645,23 +668,23 @@ static bool cmd_workspace(struct sway_config *config, int argc, char **argv) {
if (argc == 1) { if (argc == 1) {
// Handle workspace next/prev // Handle workspace next/prev
if (strcmp(argv[0], "next") == 0) { if (strcmp(argv[0], "next") == 0) {
workspace_next(); workspace_switch(workspace_next());
return true; return true;
} }
if (strcmp(argv[0], "prev") == 0) { if (strcmp(argv[0], "prev") == 0) {
workspace_next(); workspace_switch(workspace_prev());
return true; return true;
} }
// Handle workspace output_next/prev // Handle workspace output_next/prev
if (strcmp(argv[0], "next_on_output") == 0) { if (strcmp(argv[0], "next_on_output") == 0) {
workspace_output_next(); workspace_switch(workspace_output_next());
return true; return true;
} }
if (strcmp(argv[0], "prev_on_output") == 0) { if (strcmp(argv[0], "prev_on_output") == 0) {
workspace_output_prev(); workspace_switch(workspace_output_prev());
return true; return true;
} }

View file

@ -520,16 +520,25 @@ void set_view_visibility(swayc_t *view, void *data) {
if (!ASSERT_NONNULL(view)) { if (!ASSERT_NONNULL(view)) {
return; return;
} }
uint32_t *p = data; bool visible = *(bool *)data;
if (view->type == C_VIEW) { if (view->type == C_VIEW) {
wlc_view_set_mask(view->handle, *p); wlc_view_set_output(view->handle, swayc_parent_by_type(view, C_OUTPUT)->handle);
if (*p == 2) { wlc_view_set_mask(view->handle, visible ? VISIBLE : 0);
if (visible) {
wlc_view_bring_to_front(view->handle); wlc_view_bring_to_front(view->handle);
} else { } else {
wlc_view_send_to_back(view->handle); wlc_view_send_to_back(view->handle);
} }
} }
view->visible = (*p == 2); view->visible = visible;
sway_log(L_DEBUG, "Container %p is now %s", view, visible ? "visible" : "invisible");
}
void update_visibility(swayc_t *container) {
swayc_t *ws = swayc_active_workspace_for(container);
bool visible = (ws->parent->focused == ws);
sway_log(L_DEBUG, "Setting visibility of container %p to %s", container, visible ? "visible" : "invisible");
container_map(ws, set_view_visibility, &visible);
} }
void reset_gaps(swayc_t *view, void *data) { void reset_gaps(swayc_t *view, void *data) {

View file

@ -28,12 +28,11 @@ static void update_focus(swayc_t *c) {
if (parent->focused) { if (parent->focused) {
swayc_t *ws = parent->focused; swayc_t *ws = parent->focused;
// hide visibility of old workspace // hide visibility of old workspace
uint32_t mask = 1; bool visible = false;
container_map(ws, set_view_visibility, &mask); container_map(ws, set_view_visibility, &visible);
// set visibility of new workspace // set visibility of new workspace
mask = 2; visible = true;
container_map(c, set_view_visibility, &mask); container_map(c, set_view_visibility, &visible);
wlc_output_set_mask(parent->handle, 2);
destroy_workspace(ws); destroy_workspace(ws);
} }
break; break;
@ -45,8 +44,8 @@ static void update_focus(swayc_t *c) {
// for example, stacked and tabbing change stuff. // for example, stacked and tabbing change stuff.
break; break;
} }
c->parent->focused = c;
} }
c->parent->focused = c;
} }
bool move_focus(enum movement_direction direction) { bool move_focus(enum movement_direction direction) {

View file

@ -90,6 +90,9 @@ swayc_t *container_under_pointer(void) {
static bool handle_output_created(wlc_handle output) { static bool handle_output_created(wlc_handle output) {
swayc_t *op = new_output(output); swayc_t *op = new_output(output);
// Visibility mask to be able to make view invisible
wlc_output_set_mask(output, VISIBLE);
if (!op) { if (!op) {
return false; return false;
} }

View file

@ -203,6 +203,21 @@ void move_container(swayc_t *container,swayc_t* root,enum movement_direction dir
} }
void move_container_to(swayc_t* container, swayc_t* destination) {
if (container->parent == destination) {
return;
}
destroy_container(remove_child(container));
set_focused_container(get_focused_view(&root_container));
if (container->is_floating) {
add_floating(destination, container);
} else {
add_child(destination, container);
}
update_visibility(container);
arrange_windows(&root_container, -1, -1);
}
void update_geometry(swayc_t *container) { void update_geometry(swayc_t *container) {
if (container->type != C_VIEW) { if (container->type != C_VIEW) {
return; return;

5
sway/util.c Normal file
View file

@ -0,0 +1,5 @@
#include "util.h"
int wrap(int i, int max) {
return ((i % max) + max) % max;
}

View file

@ -11,6 +11,7 @@
#include "config.h" #include "config.h"
#include "stringop.h" #include "stringop.h"
#include "focus.h" #include "focus.h"
#include "util.h"
char *workspace_next_name(void) { char *workspace_next_name(void) {
sway_log(L_DEBUG, "Workspace: Generating new name"); sway_log(L_DEBUG, "Workspace: Generating new name");
@ -84,95 +85,95 @@ static bool _workspace_by_name(swayc_t *view, void *data) {
} }
swayc_t *workspace_by_name(const char* name) { swayc_t *workspace_by_name(const char* name) {
return swayc_by_test(&root_container, _workspace_by_name, (void *) name); if (strcmp(name, "prev") == 0) {
} return workspace_prev();
void workspace_output_next() {
// Get the index of the workspace in the current output, and change the view to index+1 workspace.
// if we're currently focused on the last workspace in the output, switch to the first
swayc_t *current_output = swayc_active_workspace()->parent;
int i;
for (i = 0; i < current_output->children->length - 1; i++) {
if (strcmp((((swayc_t *)current_output->children->items[i])->name), swayc_active_workspace()->name) == 0) {
workspace_switch(current_output->children->items[i + 1]);
return;
}
} }
workspace_switch(current_output->children->items[0]); else if (strcmp(name, "prev_on_output") == 0) {
} return workspace_output_prev();
void workspace_next() {
// Get the index of the workspace in the current output, and change the view to index+1 workspace.
// if we're currently focused on the last workspace in the output, change focus to there
// and call workspace_output_next(), as long as another output actually exists
swayc_t *current_output = swayc_active_workspace()->parent;
int i;
for (i = 0; i < current_output->children->length - 1; i++) {
if (strcmp((((swayc_t *)current_output->children->items[i])->name), swayc_active_workspace()->name) == 0) {
workspace_switch(current_output->children->items[i + 1]);
return;
}
} }
if (root_container.children->length > 1) { else if (strcmp(name, "next") == 0) {
for (i = 0; i < root_container.children->length - 1; i++) { return workspace_next();
if (root_container.children->items[i] == current_output) { }
workspace_switch(((swayc_t *)root_container.children->items[i + 1])->focused); else if (strcmp(name, "next_on_output") == 0) {
workspace_output_next(); return workspace_output_next();
return; }
} else if (strcmp(name, "current") == 0) {
} return swayc_active_workspace();
// If we're at the last output, then go to the first }
workspace_switch(((swayc_t *)root_container.children->items[0])->focused); else {
workspace_output_next(); return swayc_by_test(&root_container, _workspace_by_name, (void *) name);
return;
} else {
workspace_switch(current_output->children->items[0]);
} }
} }
void workspace_output_prev() { /**
// Get the index of the workspace in the current output, and change the view to index+1 workspace * Get the previous or next workspace on the specified output.
// if we're currently focused on the first workspace in the output, do nothing and return false * Wraps around at the end and beginning.
swayc_t *current_output = swayc_active_workspace()->parent; * If next is false, the previous workspace is returned, otherwise the next one is returned.
*/
swayc_t *workspace_output_prev_next_impl(swayc_t *output, bool next) {
if (!sway_assert(output->type == C_OUTPUT, "Argument must be an output, is %d", output->type)) {
return NULL;
}
int i; int i;
for (i = 1; i < current_output->children->length; i++) { for (i = 0; i < output->children->length; i++) {
if (strcmp((((swayc_t *)current_output->children->items[i])->name), swayc_active_workspace()->name) == 0) { if (output->children->items[i] == output->focused) {
workspace_switch(current_output->children->items[i - 1]); return output->children->items[wrap(i + (next ? 1 : -1), output->children->length)];
return;
} }
} }
workspace_switch(current_output->children->items[current_output->children->length - 1]);
// Doesn't happen, at worst the for loop returns the previously active workspace
return NULL;
} }
void workspace_prev() { /**
// Get the index of the workspace in the current output, and change the view to index-1 workspace. * Get the previous or next workspace. If the first/last workspace on an output is active,
// if we're currently focused on the last workspace in the output, change focus to there * proceed to the previous/next output's previous/next workspace.
// and call workspace_output_next(), as long as another output actually exists * If next is false, the previous workspace is returned, otherwise the next one is returned.
*/
swayc_t *workspace_prev_next_impl(swayc_t *workspace, bool next) {
if (!sway_assert(workspace->type == C_WORKSPACE, "Argument must be a workspace, is %d", workspace->type)) {
return NULL;
}
swayc_t *current_output = swayc_active_workspace()->parent; swayc_t *current_output = workspace->parent;
int offset = next ? 1 : -1;
int start = next ? 0 : 1;
int end = next ? (current_output->children->length) - 1 : current_output->children->length;
int i; int i;
for (i = 1; i < current_output->children->length; i++) { for (i = start; i < end; i++) {
if (strcmp((((swayc_t *)current_output->children->items[i])->name), swayc_active_workspace()->name) == 0) { if (current_output->children->items[i] == workspace) {
workspace_switch(current_output->children->items[i - 1]); return current_output->children->items[i + offset];
return;
} }
} }
if (root_container.children->length > 1) {
for (i = 1; i < root_container.children->length; i++) {
if (root_container.children->items[i] == current_output) {
workspace_switch(((swayc_t *)root_container.children->items[i - 1])->focused);
workspace_output_next();
return;
}
}
// If we're at the first output, then go to the last
workspace_switch(((swayc_t *)root_container.children->items[root_container.children->length-1])->focused);
workspace_output_next();
return;
} else {
workspace_switch(current_output->children->items[current_output->children->length - 1]);
}
// Given workspace is the first/last on the output, jump to the previous/next output
int num_outputs = root_container.children->length;
for (i = 0; i < num_outputs; i++) {
if (root_container.children->items[i] == current_output) {
swayc_t *next_output = root_container.children->items[wrap(i + offset, num_outputs)];
return workspace_output_prev_next_impl(next_output, next);
}
}
// Doesn't happen, at worst the for loop returns the previously active workspace on the active output
return NULL;
}
swayc_t *workspace_output_next() {
return workspace_output_prev_next_impl(swayc_active_output(), true);
}
swayc_t *workspace_next() {
return workspace_prev_next_impl(swayc_active_workspace(), true);
}
swayc_t *workspace_output_prev() {
return workspace_output_prev_next_impl(swayc_active_output(), false);
}
swayc_t *workspace_prev() {
return workspace_prev_next_impl(swayc_active_workspace(), false);
} }
void workspace_switch(swayc_t *workspace) { void workspace_switch(swayc_t *workspace) {