Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/bindings/keys.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ bindr=Super,Super_L,spawn,rofi -show run
| `focuslast` | - | Focus the previously active window. |
| `exchange_client` | `left/right/up/down` | Swap window with neighbor in direction. |
| `exchange_stack_client` | `next/prev` | Exchange window position in stack. |
| `move_client` | `left/right/up/down` | Move window to direction. |
| `zoom` | - | Swap focused window with Master. |

### Group
Expand Down
3 changes: 3 additions & 0 deletions src/config/parse_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,9 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
} else if (strcmp(func_name, "exchange_client") == 0) {
func = exchange_client;
(*arg).i = parse_direction(arg_value);
} else if (strcmp(func_name, "move_client") == 0) {
func = move_client;
(*arg).i = parse_direction(arg_value);
} else if (strcmp(func_name, "exchange_stack_client") == 0) {
func = exchange_stack_client;
(*arg).i = parse_circle_direction(arg_value);
Expand Down
1 change: 1 addition & 0 deletions src/dispatch/bind_declare.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ void setmfact(const Arg *arg);
void quit(const Arg *arg);
void moveresize(const Arg *arg);
void exchange_client(const Arg *arg);
void move_client(const Arg *arg);
void exchange_stack_client(const Arg *arg);
void killclient(const Arg *arg);
void toggleglobal(const Arg *arg);
Expand Down
32 changes: 32 additions & 0 deletions src/dispatch/bind_define.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,38 @@ void exchange_client(const Arg *arg) {
return;
}

void move_client(const Arg *arg) {
if (!selmon)
return;

Client *c = arg->tc ? arg->tc : selmon->sel;

if (!c || c->isfloating) {
return;
} else if ((c->isfullscreen || c->ismaximizescreen) &&
!is_scroller_layout(c->mon)) {
return;
}

Client *tc = direction_select(arg);
tc = get_focused_stack_client(tc, arg->tc);

uint32_t layout_id =
(!tc ? dirtomon(arg->i)->pertag->ltidxs[c->mon->pertag->curtag]->id
: tc->mon->pertag->ltidxs[c->mon->pertag->curtag]->id);

if (layout_id == DWINDLE) {
dwindle_move_client(c, tc, config.dwindle_split_ratio, arg->i, false);
arrange(c->mon, false, false);
} else {
move_two_client(c, tc, arg->i);
}

warp_cursor(c);

return;
}

void exchange_stack_client(const Arg *arg) {
if (!selmon)
return;
Expand Down
77 changes: 69 additions & 8 deletions src/layout/dwindle.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,16 +316,77 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay,
}
}

static void dwindle_move_client(DwindleNode **root, Client *c, Client *target,
float ratio, int32_t dir) {
if (!c || !target || c == target)
static void dwindle_move_client(Client *c1, Client *c2, float ratio,
int32_t dir, bool lock) {

if (!c1 || c1 == c2)
return;

Monitor *c_mon = c1->mon;
Monitor *t_mon = ((c2 == NULL) ? dirtomon(dir) : c2->mon);

uint32_t move_dir =
(t_mon->m.x > c_mon->m.x) * RIGHT | (t_mon->m.x < c_mon->m.x) * LEFT |
(t_mon->m.y > c_mon->m.y) * UP | (t_mon->m.y < c_mon->m.y) * DOWN;

if ((!config.exchange_cross_monitor || move_dir != dir) && c_mon != t_mon) {
return;
}

if (c_mon != t_mon) {
c1->mon = t_mon;
t_mon->sel = c1;
selmon = t_mon;

arrange(c_mon, false, false);
arrange(t_mon, false, false);
}

DwindleNode **root;
DwindleNode *c_leaf;
DwindleNode *t_leaf;

uint32_t tag = t_mon->pertag->curtag;
root = &t_mon->pertag->dwindle_root[tag];
c_leaf = dwindle_find_leaf(*root, c1);
t_leaf = dwindle_find_leaf(*root, c2);

if (!c_leaf) {
return;
}

if (c_leaf->parent && c_leaf->parent == t_leaf->parent) {
if ((move_dir == RIGHT || move_dir == UP) || t_mon == c_mon) {
DwindleNode *p = c_leaf->parent;
DwindleNode *tmp = p->first;
p->first = p->second;
p->second = tmp;
}

return;
if (!dwindle_find_leaf(*root, c) || !dwindle_find_leaf(*root, target))
}

if (!c2)
return;
dwindle_remove(root, c);
bool as_first = (dir == UP || dir == LEFT);

bool split_h = (dir == LEFT || dir == RIGHT);
dwindle_insert(root, c, target, ratio, as_first, split_h, true);

bool as_first;
if (dir == LEFT || dir == RIGHT) {
int cy = c1->geom.y + c1->geom.height / 2;
int ty = c2->geom.y + c2->geom.height / 2;
as_first = (cy < ty);
} else {
as_first = (dir == UP);
}

if (t_mon == c_mon || (move_dir == RIGHT || move_dir == LEFT)) {
dwindle_remove(root, c1);
dwindle_insert(root, c1, c2, ratio, as_first, split_h, lock);
} else {
dwindle_remove(root, c2);
dwindle_insert(root, c2, c1, ratio, as_first, split_h, lock);
}
}

static void dwindle_swap_clients(Client *c1, Client *c2) {
Expand Down Expand Up @@ -677,4 +738,4 @@ void dwindle(Monitor *m) {
void cleanup_monitor_dwindle(Monitor *m) {
for (uint32_t t = 0; t < (uint32_t)config.tag_num + 1; t++)
dwindle_free_tree(m->pertag->dwindle_root[t]);
}
}
54 changes: 52 additions & 2 deletions src/mango.c
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,7 @@ static void motionrelative(struct wl_listener *listener, void *data);
static void reset_foreign_tolevel(Client *c, Monitor *oldmon, Monitor *newmon);
static void add_foreign_topleve(Client *c);
static void exchange_two_client(Client *c1, Client *c2);
static void move_two_client(Client *c1, Client *c2, int32_t dir);
static void outputmgrapply(struct wl_listener *listener, void *data);
static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config,
int32_t test);
Expand Down Expand Up @@ -970,8 +971,8 @@ static void client_pending_maximized_state(Client *c, int32_t ismaximized);
static void client_pending_minimized_state(Client *c, int32_t isminimized);
static void scroller_insert_stack(Client *c, Client *target_client,
bool insert_before);
static void dwindle_move_client(DwindleNode **root, Client *c, Client *target,
float ratio, int32_t dir);
static void dwindle_move_client(Client *c1, Client *c2, float ratio,
int32_t dir, bool lock);
static void dwindle_resize_client_step(Monitor *m, Client *c, int32_t dx,
int32_t dy);
static void dwindle_resize_client(Monitor *m, Client *c);
Expand Down Expand Up @@ -6123,6 +6124,55 @@ void exchange_two_client(Client *c1, Client *c2) {
finish_exchange_arrange_and_focus(c1, c2, m1, m2);
}

static void move_two_client(Client *c1, Client *c2, int32_t dir) {

if (!c1 || c1 == c2) {
return;
}

Monitor *c_mon = c1->mon;
Monitor *t_mon = ((c2 == NULL) ? dirtomon(dir) : c2->mon);

uint32_t move_dir =
(t_mon->m.x > c_mon->m.x) * RIGHT | (t_mon->m.x < c_mon->m.x) * LEFT |
(t_mon->m.y > c_mon->m.y) * UP | (t_mon->m.y < c_mon->m.y) * DOWN;

if ((!config.exchange_cross_monitor || move_dir != dir) && c_mon != t_mon) {
return;
}

if (c_mon != t_mon) {
c1->mon = t_mon;
t_mon->sel = c1;
selmon = t_mon;

arrange(c_mon, false, false);
arrange(t_mon, false, false);
}

if (c2 != NULL) {

const Layout *layout = c2->mon->pertag->ltidxs[c2->mon->pertag->curtag];

if (layout->id == SCROLLER) {
exchange_two_scroller_clients(c1, c2);
return;
}

wl_list_remove(&c1->link);

if (((dir == LEFT || dir == UP) && c_mon == t_mon) ||
((move_dir == RIGHT || move_dir == UP) && c_mon != t_mon)) {
wl_list_insert(c2->link.prev, &c1->link);
} else {
wl_list_insert(&c2->link, &c1->link);
}
}

arrange(c_mon, false, false);
arrange(t_mon, false, false);
}

void set_activation_env() {
if (!getenv("DBUS_SESSION_BUS_ADDRESS")) {
mango_error(true, WLR_INFO,
Expand Down