diff --git a/include/input/cursor.h b/include/input/cursor.h index 175a9c0..021ea8a 100644 --- a/include/input/cursor.h +++ b/include/input/cursor.h @@ -15,12 +15,31 @@ struct kiwmi_cursor { struct kiwmi_server *server; struct wlr_cursor *cursor; struct wlr_xcursor_manager *xcursor_manager; + struct wl_listener cursor_motion; struct wl_listener cursor_motion_absolute; struct wl_listener cursor_button; struct wl_listener cursor_axis; struct wl_listener cursor_frame; struct wl_listener seat_request_set_cursor; + + struct { + struct wl_signal button_down; + struct wl_signal button_up; + struct wl_signal motion; + } events; +}; + +struct kiwmi_cursor_button_event { + struct wlr_event_pointer_button *wlr_event; + bool handled; +}; + +struct kiwmi_cursor_motion_event { + double oldx; + double oldy; + double newx; + double newy; }; struct kiwmi_cursor *cursor_create( diff --git a/include/luak/kiwmi_cursor.h b/include/luak/kiwmi_cursor.h new file mode 100644 index 0000000..8772d96 --- /dev/null +++ b/include/luak/kiwmi_cursor.h @@ -0,0 +1,16 @@ +/* Copyright (c), Charlotte Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef KIWMI_LUAK_KIWMI_CURSOR_H +#define KIWMI_LUAK_KIWMI_CURSOR_H + +#include + +int luaK_kiwmi_cursor_new(lua_State *L); +int luaK_kiwmi_cursor_register(lua_State *L); + +#endif /* KIWMI_LUAK_KIWMI_CURSOR_H */ diff --git a/kiwmi/input/cursor.c b/kiwmi/input/cursor.c index 048656d..8226dd1 100644 --- a/kiwmi/input/cursor.c +++ b/kiwmi/input/cursor.c @@ -62,9 +62,19 @@ cursor_motion_notify(struct wl_listener *listener, void *data) struct kiwmi_server *server = cursor->server; struct wlr_event_pointer_motion *event = data; + struct kiwmi_cursor_motion_event new_event = { + .oldx = cursor->cursor->x, + .oldy = cursor->cursor->y, + }; + wlr_cursor_move( cursor->cursor, event->device, event->delta_x, event->delta_y); + new_event.newx = cursor->cursor->x; + new_event.newy = cursor->cursor->y; + + wl_signal_emit(&cursor->events.motion, &new_event); + process_cursor_motion(server, event->time_msec); } @@ -76,8 +86,18 @@ cursor_motion_absolute_notify(struct wl_listener *listener, void *data) struct kiwmi_server *server = cursor->server; struct wlr_event_pointer_motion_absolute *event = data; + struct kiwmi_cursor_motion_event new_event = { + .oldx = cursor->cursor->x, + .oldy = cursor->cursor->y, + }; + wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y); + new_event.newx = cursor->cursor->x; + new_event.newy = cursor->cursor->y; + + wl_signal_emit(&cursor->events.motion, &new_event); + process_cursor_motion(server, event->time_msec); } @@ -90,8 +110,21 @@ cursor_button_notify(struct wl_listener *listener, void *data) struct kiwmi_input *input = &server->input; struct wlr_event_pointer_button *event = data; - wlr_seat_pointer_notify_button( - input->seat, event->time_msec, event->button, event->state); + struct kiwmi_cursor_button_event new_event = { + .wlr_event = event, + .handled = false, + }; + + if (event->state == WLR_BUTTON_PRESSED) { + wl_signal_emit(&cursor->events.button_down, &new_event); + } else { + wl_signal_emit(&cursor->events.button_up, &new_event); + } + + if (!new_event.handled) { + wlr_seat_pointer_notify_button( + input->seat, event->time_msec, event->button, event->state); + } } static void @@ -196,5 +229,9 @@ cursor_create( &server->input.seat->events.request_set_cursor, &cursor->seat_request_set_cursor); + wl_signal_init(&cursor->events.button_down); + wl_signal_init(&cursor->events.button_up); + wl_signal_init(&cursor->events.motion); + return cursor; } diff --git a/kiwmi/luak/kiwmi_cursor.c b/kiwmi/luak/kiwmi_cursor.c new file mode 100644 index 0000000..9aaa788 --- /dev/null +++ b/kiwmi/luak/kiwmi_cursor.c @@ -0,0 +1,235 @@ +/* Copyright (c), Charlotte Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "luak/kiwmi_cursor.h" + +#include + +#include +#include +#include +#include + +#include "desktop/view.h" +#include "input/cursor.h" +#include "luak/kiwmi_lua_callback.h" +#include "luak/kiwmi_view.h" +#include "luak/luak.h" + +static int +l_kiwmi_cursor_pos(lua_State *L) +{ + struct kiwmi_cursor *cursor = + *(struct kiwmi_cursor **)luaL_checkudata(L, 1, "kiwmi_cursor"); + + lua_pushnumber(L, cursor->cursor->x); + lua_pushnumber(L, cursor->cursor->y); + + return 2; +} + +static int +l_kiwmi_cursor_view_at_pos(lua_State *L) +{ + struct kiwmi_cursor *cursor = + *(struct kiwmi_cursor **)luaL_checkudata(L, 1, "kiwmi_cursor"); + + struct kiwmi_server *server = cursor->server; + + struct wlr_surface *surface; + double sx; + double sy; + + struct kiwmi_view *view = view_at( + &server->desktop, + cursor->cursor->x, + cursor->cursor->y, + &surface, + &sx, + &sy); + + if (view) { + lua_pushcfunction(L, luaK_kiwmi_view_new); + lua_pushlightuserdata(L, view); + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + } else { + lua_pushnil(L); + } + + return 1; +} + +static const luaL_Reg kiwmi_cursor_methods[] = { + {"on", luaK_callback_register_dispatch}, + {"pos", l_kiwmi_cursor_pos}, + {"view_at_pos", l_kiwmi_cursor_view_at_pos}, + {NULL, NULL}, +}; + +static void +kiwmi_cursor_on_button_down_or_up_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_cursor_button_event *event = data; + + lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); + + lua_pushinteger(L, event->wlr_event->button - BTN_LEFT + 1); + + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + return; + } + + event->handled |= lua_toboolean(L, -1); + lua_pop(L, 1); +} + +static void +kiwmi_cursor_on_motion_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_cursor_motion_event *event = data; + + lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); + + lua_newtable(L); + + lua_pushnumber(L, event->oldx); + lua_setfield(L, -2, "oldx"); + + lua_pushnumber(L, event->oldy); + lua_setfield(L, -2, "oldy"); + + lua_pushnumber(L, event->newx); + lua_setfield(L, -2, "newx"); + + lua_pushnumber(L, event->newy); + lua_setfield(L, -2, "newy"); + + if (lua_pcall(L, 1, 0, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + } +} + +static int +l_kiwmi_cursor_on_button_down(lua_State *L) +{ + struct kiwmi_cursor *cursor = + *(struct kiwmi_cursor **)luaL_checkudata(L, 1, "kiwmi_cursor"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + struct kiwmi_server *server = cursor->server; + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); + lua_pushlightuserdata(L, server); + lua_pushvalue(L, 2); + lua_pushlightuserdata(L, kiwmi_cursor_on_button_down_or_up_notify); + lua_pushlightuserdata(L, &cursor->events.button_down); + + if (lua_pcall(L, 4, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + +static int +l_kiwmi_cursor_on_button_up(lua_State *L) +{ + struct kiwmi_cursor *cursor = + *(struct kiwmi_cursor **)luaL_checkudata(L, 1, "kiwmi_cursor"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + struct kiwmi_server *server = cursor->server; + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); + lua_pushlightuserdata(L, server); + lua_pushvalue(L, 2); + lua_pushlightuserdata(L, kiwmi_cursor_on_button_down_or_up_notify); + lua_pushlightuserdata(L, &cursor->events.button_up); + + if (lua_pcall(L, 4, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + +static int +l_kiwmi_cursor_on_motion(lua_State *L) +{ + struct kiwmi_cursor *cursor = + *(struct kiwmi_cursor **)luaL_checkudata(L, 1, "kiwmi_cursor"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + struct kiwmi_server *server = cursor->server; + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); + lua_pushlightuserdata(L, server); + lua_pushvalue(L, 2); + lua_pushlightuserdata(L, kiwmi_cursor_on_motion_notify); + lua_pushlightuserdata(L, &cursor->events.motion); + + if (lua_pcall(L, 4, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + +static const luaL_Reg kiwmi_cursor_events[] = { + {"button_down", l_kiwmi_cursor_on_button_down}, + {"button_up", l_kiwmi_cursor_on_button_up}, + {"motion", l_kiwmi_cursor_on_motion}, + {NULL, NULL}, +}; + +int +luaK_kiwmi_cursor_new(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); // kiwmi_cursor + + struct kiwmi_cursor *cursor = lua_touserdata(L, 1); + + struct kiwmi_cursor **cursor_ud = lua_newuserdata(L, sizeof(*cursor_ud)); + luaL_getmetatable(L, "kiwmi_cursor"); + lua_setmetatable(L, -2); + + *cursor_ud = cursor; + + return 1; +} + +int +luaK_kiwmi_cursor_register(lua_State *L) +{ + luaL_newmetatable(L, "kiwmi_cursor"); + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, kiwmi_cursor_methods, 0); + + luaL_newlib(L, kiwmi_cursor_events); + lua_setfield(L, -2, "__events"); + + return 0; +} diff --git a/kiwmi/luak/kiwmi_server.c b/kiwmi/luak/kiwmi_server.c index efac99a..d953140 100644 --- a/kiwmi/luak/kiwmi_server.c +++ b/kiwmi/luak/kiwmi_server.c @@ -18,12 +18,29 @@ #include "desktop/view.h" #include "input/cursor.h" +#include "luak/kiwmi_cursor.h" #include "luak/kiwmi_keyboard.h" #include "luak/kiwmi_lua_callback.h" #include "luak/kiwmi_output.h" #include "luak/kiwmi_view.h" #include "server.h" +static int +l_kiwmi_server_cursor(lua_State *L) +{ + struct kiwmi_server *server = + *(struct kiwmi_server **)luaL_checkudata(L, 1, "kiwmi_server"); + + lua_pushcfunction(L, luaK_kiwmi_cursor_new); + lua_pushlightuserdata(L, server->input.cursor); + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + static int l_kiwmi_server_focused_view(lua_State *L) { @@ -77,46 +94,12 @@ l_kiwmi_server_spawn(lua_State *L) return 0; } -static int -l_kiwmi_server_view_under_cursor(lua_State *L) -{ - struct kiwmi_server *server = - *(struct kiwmi_server **)luaL_checkudata(L, 1, "kiwmi_server"); - - struct kiwmi_cursor *cursor = server->input.cursor; - - struct wlr_surface *surface; - double sx; - double sy; - - struct kiwmi_view *view = view_at( - &server->desktop, - cursor->cursor->x, - cursor->cursor->y, - &surface, - &sx, - &sy); - - if (view) { - lua_pushcfunction(L, luaK_kiwmi_view_new); - lua_pushlightuserdata(L, view); - if (lua_pcall(L, 1, 1, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - return 0; - } - } else { - lua_pushnil(L); - } - - return 1; -} - static const luaL_Reg kiwmi_server_methods[] = { + {"cursor", l_kiwmi_server_cursor}, {"focused_view", l_kiwmi_server_focused_view}, {"on", luaK_callback_register_dispatch}, {"quit", l_kiwmi_server_quit}, {"spawn", l_kiwmi_server_spawn}, - {"view_under_cursor", l_kiwmi_server_view_under_cursor}, {NULL, NULL}, }; diff --git a/kiwmi/luak/luak.c b/kiwmi/luak/luak.c index 62c2656..3552728 100644 --- a/kiwmi/luak/luak.c +++ b/kiwmi/luak/luak.c @@ -14,6 +14,7 @@ #include #include "luak/ipc.h" +#include "luak/kiwmi_cursor.h" #include "luak/kiwmi_keyboard.h" #include "luak/kiwmi_lua_callback.h" #include "luak/kiwmi_output.h" @@ -66,6 +67,8 @@ luaK_create(struct kiwmi_server *server) // register types int error = 0; + lua_pushcfunction(L, luaK_kiwmi_cursor_register); + error |= lua_pcall(L, 0, 0, 0); lua_pushcfunction(L, luaK_kiwmi_keyboard_register); error |= lua_pcall(L, 0, 0, 0); lua_pushcfunction(L, luaK_kiwmi_lua_callback_register); diff --git a/kiwmi/meson.build b/kiwmi/meson.build index 642ad37..89b63af 100644 --- a/kiwmi/meson.build +++ b/kiwmi/meson.build @@ -9,6 +9,7 @@ kiwmi_sources = files( 'input/input.c', 'input/keyboard.c', 'luak/ipc.c', + 'luak/kiwmi_cursor.c', 'luak/kiwmi_keyboard.c', 'luak/kiwmi_lua_callback.c', 'luak/kiwmi_output.c',