diff --git a/include/desktop/desktop.h b/include/desktop/desktop.h index 2ec8aa9..33eded0 100644 --- a/include/desktop/desktop.h +++ b/include/desktop/desktop.h @@ -29,10 +29,14 @@ struct kiwmi_desktop { struct { struct wl_signal new_output; struct wl_signal view_map; + struct wl_signal request_active_output; } events; }; bool desktop_init(struct kiwmi_desktop *desktop, struct wlr_renderer *renderer); void desktop_fini(struct kiwmi_desktop *desktop); +struct kiwmi_server; +struct kiwmi_output *desktop_active_output(struct kiwmi_server *server); + #endif /* KIWMI_DESKTOP_DESKTOP_H */ diff --git a/include/luak/luak.h b/include/luak/luak.h index 9b326e6..9b54c58 100644 --- a/include/luak/luak.h +++ b/include/luak/luak.h @@ -37,6 +37,7 @@ struct kiwmi_object { } events; }; +void *luaK_toudata(lua_State *L, int ud, const char *tname); int luaK_kiwmi_object_gc(lua_State *L); struct kiwmi_object *luaK_get_kiwmi_object( struct kiwmi_lua *lua, diff --git a/kiwmi/desktop/desktop.c b/kiwmi/desktop/desktop.c index 2e5b428..8edc491 100644 --- a/kiwmi/desktop/desktop.c +++ b/kiwmi/desktop/desktop.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -22,7 +23,10 @@ #include "desktop/layer_shell.h" #include "desktop/output.h" +#include "desktop/view.h" #include "desktop/xdg_shell.h" +#include "input/cursor.h" +#include "input/input.h" #include "server.h" bool @@ -67,6 +71,7 @@ desktop_init(struct kiwmi_desktop *desktop, struct wlr_renderer *renderer) wl_signal_init(&desktop->events.new_output); wl_signal_init(&desktop->events.view_map); + wl_signal_init(&desktop->events.request_active_output); return true; } @@ -76,3 +81,37 @@ desktop_fini(struct kiwmi_desktop *desktop) { wlr_output_layout_destroy(desktop->output_layout); } + +struct kiwmi_output * +desktop_active_output(struct kiwmi_server *server) +{ + // 1. callback (request_active_output) + struct kiwmi_output *output = NULL; + wl_signal_emit(&server->desktop.events.request_active_output, &output); + + if (output) { + return output; + } + + + // 2. focused view center + if (!wl_list_empty(&server->desktop.views)) { + struct kiwmi_view *view; + wl_list_for_each (view, &server->desktop.views, link) { + break; // get first element of list + } + + double lx = view->geom.x + view->geom.width / 2; + double ly = view->geom.y + view->geom.height / 2; + + struct wlr_output *wlr_output = wlr_output_layout_output_at(server->desktop.output_layout, lx, ly); + return wlr_output->data; + } + + // 3. cursor + double lx = server->input.cursor->cursor->x; + double ly = server->input.cursor->cursor->y; + + struct wlr_output *wlr_output = wlr_output_layout_output_at(server->desktop.output_layout, lx, ly); + return wlr_output->data; +} diff --git a/kiwmi/desktop/layer_shell.c b/kiwmi/desktop/layer_shell.c index edd7486..b2c823f 100644 --- a/kiwmi/desktop/layer_shell.c +++ b/kiwmi/desktop/layer_shell.c @@ -351,13 +351,9 @@ layer_shell_new_surface_notify(struct wl_listener *listener, void *data) layer_surface->namespace); if (!layer_surface->output) { - // TODO: assign active output - wlr_log(WLR_ERROR, "TODO: assign active output"); - struct kiwmi_output *output; - wl_list_for_each (output, &desktop->outputs, link) { - layer_surface->output = output->wlr_output; - break; - } + struct kiwmi_server *server = + wl_container_of(desktop, server, desktop); + layer_surface->output = desktop_active_output(server)->wlr_output; } struct kiwmi_layer *layer = malloc(sizeof(*layer)); diff --git a/kiwmi/luak/kiwmi_server.c b/kiwmi/luak/kiwmi_server.c index ff6251e..17bab2e 100644 --- a/kiwmi/luak/kiwmi_server.c +++ b/kiwmi/luak/kiwmi_server.c @@ -305,6 +305,39 @@ kiwmi_server_on_output_notify(struct wl_listener *listener, void *data) } } +static void +kiwmi_server_on_request_active_output_notify(struct wl_listener *listener, void *data) +{ + struct kiwmi_lua_callback *lc = wl_container_of(listener, lc, listener); + struct kiwmi_server *server = lc->server; + lua_State *L = server->lua->L; + struct kiwmi_output **output = data; + + lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); + if (lua_pcall(L, 0, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return; + } + + if (!lua_isnil(L, -1)) { + struct kiwmi_object *obj; + struct kiwmi_object **objp; + if (!(objp = luaK_toudata(L, -1, "kiwmi_output"))) { + wlr_log(WLR_ERROR, "kiwmi_output expected, got %s", luaL_typename(L, -1)); + return; + } + + obj = *objp; + + if (!obj->valid) { + wlr_log(WLR_ERROR, "kiwmi_output no longer valid"); + return; + } + + *output = obj->object; + } +} + static void kiwmi_server_on_view_notify(struct wl_listener *listener, void *data) { @@ -378,6 +411,30 @@ l_kiwmi_server_on_output(lua_State *L) return 0; } +static int +l_kiwmi_server_on_request_active_output(lua_State *L) +{ + struct kiwmi_object *obj = + *(struct kiwmi_object **)luaL_checkudata(L, 1, "kiwmi_server"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + struct kiwmi_server *server = obj->object; + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); + lua_pushlightuserdata(L, server); + lua_pushvalue(L, 2); + lua_pushlightuserdata(L, kiwmi_server_on_request_active_output_notify); + lua_pushlightuserdata(L, &server->desktop.events.request_active_output); + lua_pushlightuserdata(L, obj); + + if (lua_pcall(L, 5, 0, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 0; +} + static int l_kiwmi_server_on_view(lua_State *L) { @@ -405,6 +462,7 @@ l_kiwmi_server_on_view(lua_State *L) static const luaL_Reg kiwmi_server_events[] = { {"keyboard", l_kiwmi_server_on_keyboard}, {"output", l_kiwmi_server_on_output}, + {"request_active_output", l_kiwmi_server_on_request_active_output}, {"view", l_kiwmi_server_on_view}, {NULL, NULL}, }; diff --git a/kiwmi/luak/luak.c b/kiwmi/luak/luak.c index 79677fd..6e2c2a6 100644 --- a/kiwmi/luak/luak.c +++ b/kiwmi/luak/luak.c @@ -22,6 +22,22 @@ #include "luak/kiwmi_server.h" #include "luak/kiwmi_view.h" +void * +luaK_toudata(lua_State *L, int ud, const char *tname) +{ + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + } + return NULL; +} + int luaK_kiwmi_object_gc(lua_State *L) { diff --git a/lua_docs.md b/lua_docs.md index 8434097..1ec953b 100644 --- a/lua_docs.md +++ b/lua_docs.md @@ -58,6 +58,13 @@ Get the view at a specified position. A new keyboard got attached. Callback receives a reference to the keyboard. +#### request_active_output + +Called when the active output needs to be requested (for example because a layer-shell surface needs to be positioned). +Callback receives nothing and optionally returns a kiwmi_output. + +If this isn't set or returns `nil`, the compositor defaults to the output the focused view is on, and if there is no view, the output the mouse is on. + #### output A new output got attached.