diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 5379ddca..25bad217 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1018,6 +1018,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); diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index a04ba0c1..554b7134 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -31,6 +31,7 @@ int32_t setmfact(const Arg *arg); int32_t quit(const Arg *arg); int32_t moveresize(const Arg *arg); int32_t exchange_client(const Arg *arg); +int32_t move_client(const Arg *arg); int32_t exchange_stack_client(const Arg *arg); int32_t killclient(const Arg *arg); int32_t toggleglobal(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index cf0f770a..098dca43 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -111,6 +111,33 @@ int32_t exchange_client(const Arg *arg) { return 0; } +int32_t move_client(const Arg *arg) { + if (!selmon) + return 0; + Client *c = arg->tc ? arg->tc : selmon->sel; + if (!c || c->isfloating) + return 0; + + if ((c->isfullscreen || c->ismaximizescreen) && !is_scroller_layout(c->mon)) + return 0; + + Client *tc = direction_select(arg); + tc = get_focused_stack_client(tc, arg->tc); + + if (!tc) + return 0; + + if (c->mon && c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == DWINDLE) { + uint32_t tag = c->mon->pertag->curtag; + dwindle_move_client(&c->mon->pertag->dwindle_root[tag], c, tc, + config.dwindle_split_ratio, arg->i, false); + arrange(c->mon, false, false); + } else { + move_two_client(c, tc, arg->i); + } + return 0; +} + int32_t exchange_stack_client(const Arg *arg) { if (!selmon) return 0; diff --git a/src/layout/dwindle.h b/src/layout/dwindle.h index 74e79477..7e102f98 100644 --- a/src/layout/dwindle.h +++ b/src/layout/dwindle.h @@ -286,15 +286,33 @@ 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) { + float ratio, int32_t dir, bool lock) { if (!c || !target || c == target) return; - if (!dwindle_find_leaf(*root, c) || !dwindle_find_leaf(*root, target)) + DwindleNode *c_leaf = dwindle_find_leaf(*root, c); + DwindleNode *t_leaf = dwindle_find_leaf(*root, target); + if (!c_leaf || !t_leaf) return; - dwindle_remove(root, c); - bool as_first = (dir == UP || dir == LEFT); + + if (c_leaf->parent && c_leaf->parent == t_leaf->parent) { + DwindleNode *p = c_leaf->parent; + DwindleNode *tmp = p->first; + p->first = p->second; + p->second = tmp; + return; + } + 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 = c->geom.y + c->geom.height / 2; + int ty = target->geom.y + target->geom.height / 2; + as_first = (cy < ty); + } else { + as_first = (dir == UP); + } + dwindle_remove(root, c); + dwindle_insert(root, c, target, ratio, as_first, split_h, lock); } static void dwindle_swap_clients(Client *c1, Client *c2) { diff --git a/src/mango.c b/src/mango.c index 74d4c196..4365f370 100644 --- a/src/mango.c +++ b/src/mango.c @@ -717,6 +717,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 *c, Client *target, int32_t dir); static void outputmgrapply(struct wl_listener *listener, void *data); static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int32_t test); @@ -878,7 +879,7 @@ 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); + 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); @@ -5177,6 +5178,30 @@ void exchange_two_client(Client *c1, Client *c2) { finish_exchange_arrange_and_focus(c1, c2, m1, m2); } +static void move_two_client(Client *c, Client *target, int32_t dir) { + if (c == NULL || target == NULL || c == target || + (!config.exchange_cross_monitor && c->mon != target->mon)) { + return; + } + + Monitor *m = c->mon; + const Layout *layout = m->pertag->ltidxs[m->pertag->curtag]; + + if (layout->id == SCROLLER) { + exchange_two_scroller_clients(c, target); + return; + } + + wl_list_remove(&c->link); + if (dir == UP || dir == LEFT) { + wl_list_insert(target->link.prev, &c->link); + } else { + wl_list_insert(&target->link, &c->link); + } + + arrange(m, false, false); +} + void set_activation_env() { if (!getenv("DBUS_SESSION_BUS_ADDRESS")) { wlr_log(WLR_INFO, "Not updating dbus execution environment: "