Preserve floating positions across directed output moves
d85b756f4cefac6461bb7669ddb5d6416231d3b5
1 parent
69879553
swm.c
+19 -3
| 5286 | 5286 | ||
| 5287 | 5287 | if (mv && sel) |
|
| 5288 | 5288 | focus_client(sel, 1); |
|
| 5289 | 5289 | } |
|
| 5290 | 5290 | ||
| 5291 | + | /* Preserve a window's position relative to its display during directed moves. */ |
|
| 5292 | + | static void client_translate_monitor(client_t *c, monitor_t *oldmon, monitor_t *newmon) { |
|
| 5293 | + | struct wlr_box *geom; |
|
| 5294 | + | ||
| 5295 | + | if (!c || !oldmon || !newmon || oldmon == newmon) |
|
| 5296 | + | return; |
|
| 5297 | + | geom = c->is_fullscreen ? &c->prev : &c->geom; |
|
| 5298 | + | geom->x += newmon->m.x - oldmon->m.x; |
|
| 5299 | + | geom->y += newmon->m.y - oldmon->m.y; |
|
| 5300 | + | } |
|
| 5301 | + | ||
| 5291 | 5302 | /* Fit a window to the display it was just moved to. */ |
|
| 5292 | 5303 | void client_place(client_t *c) { |
|
| 5293 | 5304 | /* An initial commit may assign a monitor before map_notify() creates the |
|
| 5294 | 5305 | * client's scene tree. Defer all scene operations until the surface maps. */ |
|
| 5295 | 5306 | if (!c->mon || !client_surface(c)->mapped) |
| 5348 | 5359 | oldmon = main->mon; |
|
| 5349 | 5360 | wl_list_for_each(w, &clients, link) { |
|
| 5350 | 5361 | if (!clients_related(w, main)) |
|
| 5351 | 5362 | continue; |
|
| 5352 | 5363 | w->ws = ws; |
|
| 5353 | - | ||
| 5354 | 5364 | if (ws->mon && ws->mon != w->mon) { |
|
| 5365 | + | client_translate_monitor(w, w->mon, ws->mon); |
|
| 5355 | 5366 | client_assign_monitor(w, ws->mon); |
|
| 5356 | 5367 | ||
| 5357 | 5368 | if (!w->is_fullscreen) |
|
| 5358 | 5369 | w->prev = w->geom; |
|
| 5359 | 5370 | client_place(w); |
| 5383 | 5394 | wl_list_for_each(c, &clients, link) { |
|
| 5384 | 5395 | if (c->ws != ws) |
|
| 5385 | 5396 | continue; |
|
| 5386 | 5397 | ||
| 5387 | 5398 | if (c->mon != m) { |
|
| 5399 | + | client_translate_monitor(c, c->mon, m); |
|
| 5388 | 5400 | client_assign_monitor(c, m); |
|
| 5389 | 5401 | ||
| 5390 | 5402 | if (!c->is_fullscreen) |
|
| 5391 | 5403 | c->prev = c->geom; |
|
| 5392 | 5404 | resize(c, c->geom, 0); |
| 6210 | 6222 | ||
| 6211 | 6223 | /* Move the focused window to the workspace on a neighboring display. */ |
|
| 6212 | 6224 | void tag_monitor(const arg_t *arg) { |
|
| 6213 | 6225 | client_t *sel = focus_top(selmon); |
|
| 6214 | 6226 | ||
| 6215 | - | if (sel) |
|
| 6216 | - | set_monitor(sel, direction_to_monitor(arg->i), nullptr); |
|
| 6227 | + | if (sel) { |
|
| 6228 | + | monitor_t *target = direction_to_monitor(arg->i); |
|
| 6229 | + | ||
| 6230 | + | client_translate_monitor(sel, sel->mon, target); |
|
| 6231 | + | set_monitor(sel, target, nullptr); |
|
| 6232 | + | } |
|
| 6217 | 6233 | } |
|
| 6218 | 6234 | ||
| 6219 | 6235 | /* Adjust the master size, master count, stack count, or layout direction. */ |
|
| 6220 | 6236 | void stack_config(const arg_t *arg) { |
|
| 6221 | 6237 | /* adjust the master/stack parameters of the focused workspace's |
test/unit.c
+15 -0
| 385 | 385 | scaled_surface = nullptr; |
|
| 386 | 386 | monitor_set_scale(&monitor); |
|
| 387 | 387 | assert(scaled_surface == &surface); |
|
| 388 | 388 | } |
|
| 389 | 389 | ||
| 390 | + | /* Verify directed output moves preserve a window's display-relative position. */ |
|
| 391 | + | static void test_monitor_translation(void) { |
|
| 392 | + | monitor_t oldmon = { .m = { 0, 0, 1920, 1080 } }; |
|
| 393 | + | monitor_t newmon = { .m = { 1920, 100, 2560, 1440 } }; |
|
| 394 | + | client_t client = { .geom = { 100, 50, 640, 480 }, .prev = { 200, 75, 800, 600 } }; |
|
| 395 | + | ||
| 396 | + | client_translate_monitor(&client, &oldmon, &newmon); |
|
| 397 | + | assert(client.geom.x == 2020 && client.geom.y == 150); |
|
| 398 | + | ||
| 399 | + | client.is_fullscreen = true; |
|
| 400 | + | client_translate_monitor(&client, &newmon, &oldmon); |
|
| 401 | + | assert(client.prev.x == -1720 && client.prev.y == -25); |
|
| 402 | + | } |
|
| 403 | + | ||
| 390 | 404 | /* Verify matching rules update client state and workspace assignment. */ |
|
| 391 | 405 | static void test_rule_application(void) { |
|
| 392 | 406 | client_t client; |
|
| 393 | 407 | struct wlr_xdg_surface surface; |
|
| 394 | 408 | struct wlr_xdg_toplevel toplevel; |
| 1137 | 1151 | { "shortcut-release", test_shortcut_release }, |
|
| 1138 | 1152 | { "input-method", test_input_method_lifecycle }, |
|
| 1139 | 1153 | { "output-role-scale-change", test_output_role_scale_change }, |
|
| 1140 | 1154 | { "input-early-paths", test_input_early_paths }, |
|
| 1141 | 1155 | { "command-line", test_command_line_errors }, |
|
| 1156 | + | { "monitor-translation", test_monitor_translation }, |
|
| 1142 | 1157 | { "pointer-and-decoration", test_pointer_and_decoration_lifecycle }, |
|
| 1143 | 1158 | { "keybindings-and-repeat", test_keybindings_and_repeat }, |
|
| 1144 | 1159 | }; |
|
| 1145 | 1160 | ||
| 1146 | 1161 | if (argc == 2 && !strcmp(argv[1], "--list")) { |