Preserve floating positions across directed output moves

d85b756f4cefac6461bb7669ddb5d6416231d3b5
Alexis Sellier committed ago 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")) {