diff --git a/objects/client.c b/objects/client.c index 94897aad..e21c2ab9 100644 --- a/objects/client.c +++ b/objects/client.c @@ -2343,13 +2343,11 @@ luaA_client_swap(lua_State *L) luaA_object_push(L, swap); lua_pushboolean(L, true); luaA_object_emit_signal(L, -4, "swapped", 2); - lua_pop(L, 2); luaA_object_push(L, swap); luaA_object_push(L, c); lua_pushboolean(L, false); luaA_object_emit_signal(L, -3, "swapped", 2); - lua_pop(L, 3); } return 0; diff --git a/objects/screen.c b/objects/screen.c index 88586055..8f401d65 100644 --- a/objects/screen.c +++ b/objects/screen.c @@ -79,6 +79,16 @@ * @signal removed */ +/** This signal is emitted when the list of available screens changes. + * @signal .list + */ + +/** When 2 screens are swapped + * @tparam screen screen The other screen + * @tparam boolean is_source If self is the source or the destination of the swap + * @signal .swapped + */ + /** * The primary screen. * @@ -603,6 +613,7 @@ screen_refresh(void) screen_array_t new_screens; lua_State *L = globalconf_get_lua_State(); + bool list_changed = false; screen_array_init(&new_screens); if (globalconf.have_randr_15) @@ -624,6 +635,8 @@ screen_refresh(void) * globalconf.screens reference this screen now */ luaA_object_push(L, *new_screen); luaA_object_ref(L, -1); + + list_changed = true; } } @@ -642,6 +655,8 @@ screen_refresh(void) lua_pop(L, 1); luaA_object_unref(L, old_screen); old_screen->valid = false; + + list_changed = true; } } @@ -656,6 +671,9 @@ screen_refresh(void) screen_array_wipe(&new_screens); screen_update_primary(); + + if (list_changed) + luaA_class_emit_signal(L, &screen_class, "list", 0); } /** Return the squared distance of the given screen to the coordinates. @@ -1088,6 +1106,7 @@ luaA_screen_fake_add(lua_State *L) s->geometry.height = height; screen_added(L, s); + luaA_class_emit_signal(L, &screen_class, "list", 0); luaA_object_push(L, s); return 1; @@ -1109,6 +1128,7 @@ luaA_screen_fake_remove(lua_State *L) luaA_object_push(L, s); screen_removed(L, -1); lua_pop(L, 1); + luaA_class_emit_signal(L, &screen_class, "list", 0); luaA_object_unref(L, s); s->valid = false; @@ -1145,6 +1165,47 @@ luaA_screen_fake_resize(lua_State *L) return 0; } +/** Swap a screen with another one in global screen list. + * @client s A screen to swap with. + * @function swap + */ +static int +luaA_screen_swap(lua_State *L) +{ + screen_t *s = luaA_checkudata(L, 1, &screen_class); + screen_t *swap = luaA_checkudata(L, 2, &screen_class); + + if(s != swap) + { + screen_t **ref_s = NULL, **ref_swap = NULL; + foreach(item, globalconf.screens) + { + if(*item == s) + ref_s = item; + else if(*item == swap) + ref_swap = item; + if(ref_s && ref_swap) + break; + } + /* swap ! */ + *ref_s = swap; + *ref_swap = s; + + luaA_class_emit_signal(L, &screen_class, "list", 0); + + luaA_object_push(L, swap); + lua_pushboolean(L, true); + luaA_object_emit_signal(L, -4, "swapped", 2); + + luaA_object_push(L, swap); + luaA_object_push(L, s); + lua_pushboolean(L, false); + luaA_object_emit_signal(L, -3, "swapped", 2); + } + + return 0; +} + void screen_class_setup(lua_State *L) { @@ -1165,6 +1226,7 @@ screen_class_setup(lua_State *L) LUA_CLASS_META { "fake_remove", luaA_screen_fake_remove }, { "fake_resize", luaA_screen_fake_resize }, + { "swap", luaA_screen_swap }, { NULL, NULL }, }; diff --git a/tests/test-client-swap.lua b/tests/test-client-swap.lua new file mode 100644 index 00000000..6ed96828 --- /dev/null +++ b/tests/test-client-swap.lua @@ -0,0 +1,33 @@ +-- Test if client's c:swap() corrupts the Lua stack + +local runner = require("_runner") +local test_client = require("_client") + +runner.run_steps({ + -- Spawn two clients + function(count) + if count == 1 then + test_client() + test_client() + end + if #client.get() >= 2 then + return true + end + end, + + -- Swap them + function() + assert(#client.get() == 2, #client.get()) + local c1 = client.get()[1] + local c2 = client.get()[2] + + c2:swap(c1) + c1:swap(c2) + c1:swap(c2) + c1:swap(c2) + c2:swap(c1) + return true + end, +}) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/tests/test-screen-changes.lua b/tests/test-screen-changes.lua index 0e1a83ce..68d624ad 100644 --- a/tests/test-screen-changes.lua +++ b/tests/test-screen-changes.lua @@ -9,6 +9,11 @@ local real_screen = screen[1] local fake_screen = screen.fake_add(50, 50, 500, 500) local test_client1, test_client2 +local list_count = 0 +screen.connect_signal("list", function() + list_count = list_count + 1 +end) + local steps = { -- Step 1: Set up some clients to experiment with and assign them as needed function(count) @@ -53,6 +58,15 @@ local steps = { assert(wb.y == 110, wb.y) assert(wb.width == 600, wb.width) + -- Test screen order changes + assert(list_count == 0) + assert(screen[1] == real_screen) + assert(screen[2] == fake_screen) + real_screen:swap(fake_screen) + assert(list_count == 1) + assert(screen[2] == real_screen) + assert(screen[1] == fake_screen) + return true end,