diff --git a/include/desktop/desktop_surface.h b/include/desktop/desktop_surface.h index 4efe0cd..d0de3ab 100644 --- a/include/desktop/desktop_surface.h +++ b/include/desktop/desktop_surface.h @@ -8,6 +8,9 @@ #ifndef KIWMI_DESKTOP_DESKTOP_SURFACE_H #define KIWMI_DESKTOP_DESKTOP_SURFACE_H +struct wlr_surface; +struct kiwmi_desktop; + enum kiwmi_desktop_surface_type { KIWMI_DESKTOP_SURFACE_VIEW, KIWMI_DESKTOP_SURFACE_LAYER, @@ -22,6 +25,21 @@ struct kiwmi_desktop_surface { struct wlr_scene_tree *popups_tree; enum kiwmi_desktop_surface_type type; + const struct kiwmi_desktop_surface_impl *impl; }; +struct kiwmi_desktop_surface_impl { + struct kiwmi_output *(*get_output)( + struct kiwmi_desktop_surface *desktop_surface); +}; + +struct kiwmi_desktop_surface * +desktop_surface_at(struct kiwmi_desktop *desktop, double lx, double ly); +struct kiwmi_output * +desktop_surface_get_output(struct kiwmi_desktop_surface *desktop_surface); +void desktop_surface_get_pos( + struct kiwmi_desktop_surface *desktop_surface, + int *lx, + int *ly); + #endif /* KIWMI_DESKTOP_DESKTOP_SURFACE_H */ diff --git a/include/desktop/view.h b/include/desktop/view.h index 3a42617..72c9163 100644 --- a/include/desktop/view.h +++ b/include/desktop/view.h @@ -147,21 +147,9 @@ void view_set_size(struct kiwmi_view *view, uint32_t width, uint32_t height); void view_set_pos(struct kiwmi_view *view, uint32_t x, uint32_t y); void view_set_tiled(struct kiwmi_view *view, enum wlr_edges edges); void view_set_hidden(struct kiwmi_view *view, bool hidden); -struct wlr_surface *view_surface_at( - struct kiwmi_view *view, - double sx, - double sy, - double *sub_x, - double *sub_y); void view_focus(struct kiwmi_view *view); -struct kiwmi_view *view_at( - struct kiwmi_desktop *desktop, - double lx, - double ly, - struct wlr_surface **surface, - double *sx, - double *sy); +struct kiwmi_view *view_at(struct kiwmi_desktop *desktop, double lx, double ly); void view_move(struct kiwmi_view *view); void view_resize(struct kiwmi_view *view, uint32_t edges); struct kiwmi_view *view_create( diff --git a/kiwmi/desktop/desktop.c b/kiwmi/desktop/desktop.c index 9bbeb48..7e3531a 100644 --- a/kiwmi/desktop/desktop.c +++ b/kiwmi/desktop/desktop.c @@ -22,6 +22,7 @@ #include #include +#include "desktop/desktop_surface.h" #include "desktop/layer_shell.h" #include "desktop/output.h" #include "desktop/stratum.h" @@ -29,6 +30,7 @@ #include "desktop/xdg_shell.h" #include "input/cursor.h" #include "input/input.h" +#include "input/seat.h" #include "server.h" bool @@ -127,19 +129,14 @@ desktop_active_output(struct kiwmi_server *server) 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 + // 2. focused view + struct kiwmi_view *focused_view = server->input.seat->focused_view; + if (focused_view) { + output = desktop_surface_get_output(&focused_view->desktop_surface); + + if (output) { + return output; } - - double lx = view->x + view->geom.width / 2; - double ly = view->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 diff --git a/kiwmi/desktop/desktop_surface.c b/kiwmi/desktop/desktop_surface.c new file mode 100644 index 0000000..452205e --- /dev/null +++ b/kiwmi/desktop/desktop_surface.c @@ -0,0 +1,87 @@ +/* Copyright (c), Niclas 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 "desktop/desktop_surface.h" + +#include +#include +#include +#include + +#include "desktop/desktop.h" +#include "desktop/layer_shell.h" +#include "desktop/output.h" +#include "desktop/popup.h" +#include "desktop/view.h" + +static struct kiwmi_desktop_surface * +desktop_surface_from_wlr_surface(struct wlr_surface *surface) +{ + struct wlr_subsurface *subsurface; + while (wlr_surface_is_subsurface(surface)) { + subsurface = wlr_subsurface_from_wlr_surface(surface); + surface = subsurface->parent; + } + + if (wlr_surface_is_xdg_surface(surface)) { + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_from_wlr_surface(surface); + switch (xdg_surface->role) { + case WLR_XDG_SURFACE_ROLE_TOPLEVEL:; + struct kiwmi_view *view = xdg_surface->data; + return &view->desktop_surface; + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + return popup_get_desktop_surface(xdg_surface->popup); + break; + default: + return NULL; + break; + } + } else if (wlr_surface_is_layer_surface(surface)) { + struct wlr_layer_surface_v1 *layer_surface = + wlr_layer_surface_v1_from_wlr_surface(surface); + struct kiwmi_layer *layer = layer_surface->data; + return &layer->desktop_surface; + } + + return NULL; +} + +struct kiwmi_desktop_surface * +desktop_surface_at(struct kiwmi_desktop *desktop, double lx, double ly) +{ + double sx, sy; // unused + struct wlr_scene_node *node_at = + wlr_scene_node_at(&desktop->scene->node, lx, ly, &sx, &sy); + + if (!node_at || node_at->type != WLR_SCENE_NODE_SURFACE) { + return NULL; + } + + struct wlr_surface *surface = wlr_scene_surface_from_node(node_at)->surface; + return desktop_surface_from_wlr_surface(surface); +} + +struct kiwmi_output * +desktop_surface_get_output(struct kiwmi_desktop_surface *desktop_surface) +{ + if (desktop_surface->impl && desktop_surface->impl->get_output) { + return desktop_surface->impl->get_output(desktop_surface); + } else { + return NULL; + } +} + +void +desktop_surface_get_pos( + struct kiwmi_desktop_surface *desktop_surface, + int *lx, + int *ly) +{ + wlr_scene_node_coords(&desktop_surface->tree->node, lx, ly); +} diff --git a/kiwmi/desktop/layer_shell.c b/kiwmi/desktop/layer_shell.c index f504306..3853c28 100644 --- a/kiwmi/desktop/layer_shell.c +++ b/kiwmi/desktop/layer_shell.c @@ -390,6 +390,18 @@ layer_at( return NULL; } +static struct kiwmi_output * +layer_desktop_surface_get_output(struct kiwmi_desktop_surface *desktop_surface) +{ + struct kiwmi_layer *layer = + wl_container_of(desktop_surface, layer, desktop_surface); + return layer->output; +} + +static const struct kiwmi_desktop_surface_impl layer_desktop_surface_impl = { + .get_output = layer_desktop_surface_get_output, +}; + void layer_shell_new_surface_notify(struct wl_listener *listener, void *data) { @@ -431,6 +443,7 @@ layer_shell_new_surface_notify(struct wl_listener *listener, void *data) layer->layer = layer_surface->current.layer; layer->desktop_surface.type = KIWMI_DESKTOP_SURFACE_LAYER; + layer->desktop_surface.impl = &layer_desktop_surface_impl; layer->destroy.notify = kiwmi_layer_destroy_notify; wl_signal_add(&layer_surface->events.destroy, &layer->destroy); diff --git a/kiwmi/desktop/view.c b/kiwmi/desktop/view.c index 0f54f26..4bba2ad 100644 --- a/kiwmi/desktop/view.c +++ b/kiwmi/desktop/view.c @@ -8,6 +8,7 @@ #include "desktop/view.h" #include +#include #include #include "desktop/output.h" @@ -104,17 +105,13 @@ view_set_pos(struct kiwmi_view *view, uint32_t x, uint32_t y) wlr_scene_node_set_position(&view->desktop_surface.tree->node, x, y); wlr_scene_node_set_position(&view->desktop_surface.popups_tree->node, x, y); - struct kiwmi_view_child *child; - wl_list_for_each (child, &view->children, link) { - if (child->impl && child->impl->reconfigure) { - child->impl->reconfigure(child); - } + int lx, ly; // unused + // If it is enabled (as well as all its parents) + if (wlr_scene_node_coords(&view->desktop_surface.tree->node, &lx, &ly)) { + struct kiwmi_server *server = + wl_container_of(view->desktop, server, desktop); + cursor_refresh_focus(server->input.cursor, NULL, NULL, NULL); } - - struct kiwmi_desktop *desktop = view->desktop; - struct kiwmi_server *server = wl_container_of(desktop, server, desktop); - struct kiwmi_cursor *cursor = server->input.cursor; - cursor_refresh_focus(cursor, NULL, NULL, NULL); } void @@ -139,69 +136,20 @@ view_set_hidden(struct kiwmi_view *view, bool hidden) &view->desktop_surface.popups_tree->node, !hidden); } -struct wlr_surface * -view_surface_at( - struct kiwmi_view *view, - double sx, - double sy, - double *sub_x, - double *sub_y) -{ - if (view->impl->surface_at) { - return view->impl->surface_at(view, sx, sy, sub_x, sub_y); - } - - return NULL; -} - -static bool -surface_at( - struct kiwmi_view *view, - struct wlr_surface **surface, - double lx, - double ly, - double *sx, - double *sy) -{ - double view_sx = lx - view->x + view->geom.x; - double view_sy = ly - view->y + view->geom.y; - - double _sx; - double _sy; - struct wlr_surface *_surface = - view_surface_at(view, view_sx, view_sy, &_sx, &_sy); - - if (_surface) { - *sx = _sx; - *sy = _sy; - *surface = _surface; - return true; - } - - return false; -} - struct kiwmi_view * -view_at( - struct kiwmi_desktop *desktop, - double lx, - double ly, - struct wlr_surface **surface, - double *sx, - double *sy) +view_at(struct kiwmi_desktop *desktop, double lx, double ly) { - struct kiwmi_view *view; - wl_list_for_each (view, &desktop->views, link) { - if (view->hidden || !view->mapped) { - continue; - } + struct kiwmi_desktop_surface *desktop_surface = + desktop_surface_at(desktop, lx, ly); - if (surface_at(view, surface, lx, ly, sx, sy)) { - return view; - } + if (!desktop_surface + || desktop_surface->type != KIWMI_DESKTOP_SURFACE_VIEW) { + return NULL; } - return NULL; + struct kiwmi_view *view = + wl_container_of(desktop_surface, view, desktop_surface); + return view; } static void @@ -228,17 +176,20 @@ view_begin_interactive( cursor->cursor_mode = mode; cursor->grabbed.view = view; + int view_lx, view_ly; + desktop_surface_get_pos(&view->desktop_surface, &view_lx, &view_ly); + if (mode == KIWMI_CURSOR_MOVE) { - cursor->grabbed.orig_x = cursor->cursor->x - view->x; - cursor->grabbed.orig_y = cursor->cursor->y - view->y; + cursor->grabbed.orig_x = cursor->cursor->x - view_lx; + cursor->grabbed.orig_y = cursor->cursor->y - view_ly; } else { cursor->grabbed.orig_x = cursor->cursor->x; cursor->grabbed.orig_y = cursor->cursor->y; cursor->grabbed.resize_edges = edges; } - cursor->grabbed.orig_geom.x = view->x; - cursor->grabbed.orig_geom.y = view->y; + cursor->grabbed.orig_geom.x = view_lx; + cursor->grabbed.orig_geom.y = view_ly; cursor->grabbed.orig_geom.width = width; cursor->grabbed.orig_geom.height = height; } @@ -280,6 +231,37 @@ view_init_subsurfaces(struct kiwmi_view_child *child, struct kiwmi_view *view) } } +static struct kiwmi_output * +view_desktop_surface_get_output(struct kiwmi_desktop_surface *desktop_surface) +{ + struct kiwmi_view *view = + wl_container_of(desktop_surface, view, desktop_surface); + + int lx, ly; + desktop_surface_get_pos(&view->desktop_surface, &lx, &ly); + + // Prefer view center + struct wlr_output *output = wlr_output_layout_output_at( + view->desktop->output_layout, + lx + view->geom.width / 2, + ly + view->geom.height / 2); + if (output) { + return (struct kiwmi_output *)output->data; + } + + // Retry top-left corner + output = wlr_output_layout_output_at(view->desktop->output_layout, lx, ly); + if (output) { + return (struct kiwmi_output *)output->data; + } + + return NULL; +} + +static const struct kiwmi_desktop_surface_impl view_desktop_surface_impl = { + .get_output = view_desktop_surface_get_output, +}; + struct kiwmi_view * view_create( struct kiwmi_desktop *desktop, @@ -305,6 +287,7 @@ view_create( wl_list_init(&view->children); view->desktop_surface.type = KIWMI_DESKTOP_SURFACE_VIEW; + view->desktop_surface.impl = &view_desktop_surface_impl; wl_signal_init(&view->events.unmap); wl_signal_init(&view->events.request_move); diff --git a/kiwmi/desktop/xdg_shell.c b/kiwmi/desktop/xdg_shell.c index 16808e6..d44a53e 100644 --- a/kiwmi/desktop/xdg_shell.c +++ b/kiwmi/desktop/xdg_shell.c @@ -181,19 +181,20 @@ xdg_surface_unmap_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_view *view = wl_container_of(listener, view, unmap); - if (view->mapped) { - view->mapped = false; + view->mapped = false; + int lx, ly; // unused + if (wlr_scene_node_coords(&view->desktop_surface.tree->node, &lx, &ly)) { wlr_scene_node_set_enabled(&view->desktop_surface.tree->node, false); wlr_scene_node_set_enabled( &view->desktop_surface.popups_tree->node, false); - struct kiwmi_desktop *desktop = view->desktop; - struct kiwmi_server *server = wl_container_of(desktop, server, desktop); + struct kiwmi_server *server = + wl_container_of(view->desktop, server, desktop); cursor_refresh_focus(server->input.cursor, NULL, NULL, NULL); - - wl_signal_emit(&view->events.unmap, view); } + + wl_signal_emit(&view->events.unmap, view); } static void diff --git a/kiwmi/input/cursor.c b/kiwmi/input/cursor.c index 7fce94a..beda260 100644 --- a/kiwmi/input/cursor.c +++ b/kiwmi/input/cursor.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -284,72 +285,24 @@ cursor_refresh_focus( struct kiwmi_desktop *desktop = &cursor->server->desktop; struct wlr_seat *seat = cursor->server->input.seat->seat; - double ox = cursor->cursor->x; - double oy = cursor->cursor->y; - struct wlr_output *wlr_output = wlr_output_layout_output_at( - desktop->output_layout, cursor->cursor->x, cursor->cursor->y); - - wlr_output_layout_output_coords( - desktop->output_layout, wlr_output, &ox, &oy); - - struct kiwmi_output *output = wlr_output->data; - struct wlr_surface *surface = NULL; double sx; double sy; - struct kiwmi_layer *layer = layer_at( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &surface, - ox, - oy, - &sx, - &sy); - struct kiwmi_view *view; + struct wlr_scene_node *node_at = wlr_scene_node_at( + &desktop->scene->node, cursor->cursor->x, cursor->cursor->y, &sx, &sy); - if (!layer) { - layer = layer_at( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &surface, - ox, - oy, - &sx, - &sy); - } + if (node_at && node_at->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node_at); + surface = scene_surface->surface; - if (!layer) { - view = view_at( - desktop, cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - } - - if (!layer) { - layer = layer_at( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &surface, - ox, - oy, - &sx, - &sy); - } - - if (!layer) { - layer = layer_at( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &surface, - ox, - oy, - &sx, - &sy); - } - - if (!layer && !view) { + if (surface != seat->pointer_state.focused_surface) { + wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + } + } else { wlr_xcursor_manager_set_cursor_image( cursor->xcursor_manager, "left_ptr", cursor->cursor); - } - - if (surface && surface != seat->pointer_state.focused_surface) { - wlr_seat_pointer_notify_enter(seat, surface, sx, sy); - } else if (!surface) { wlr_seat_pointer_clear_focus(seat); } diff --git a/kiwmi/luak/kiwmi_cursor.c b/kiwmi/luak/kiwmi_cursor.c index 89dcf07..edd8c00 100644 --- a/kiwmi/luak/kiwmi_cursor.c +++ b/kiwmi/luak/kiwmi_cursor.c @@ -73,17 +73,8 @@ l_kiwmi_cursor_view_at_pos(lua_State *L) struct kiwmi_cursor *cursor = obj->object; 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); + struct kiwmi_view *view = + view_at(&server->desktop, cursor->cursor->x, cursor->cursor->y); if (view) { lua_pushcfunction(L, luaK_kiwmi_view_new); diff --git a/kiwmi/luak/kiwmi_server.c b/kiwmi/luak/kiwmi_server.c index f8f61a3..ec0bccc 100644 --- a/kiwmi/luak/kiwmi_server.c +++ b/kiwmi/luak/kiwmi_server.c @@ -313,12 +313,7 @@ l_kiwmi_server_view_at(lua_State *L) double lx = lua_tonumber(L, 2); double ly = lua_tonumber(L, 3); - struct wlr_surface *surface; - double sx; - double sy; - - struct kiwmi_view *view = - view_at(&server->desktop, lx, ly, &surface, &sx, &sy); + struct kiwmi_view *view = view_at(&server->desktop, lx, ly); if (view) { lua_pushcfunction(L, luaK_kiwmi_view_new); diff --git a/kiwmi/luak/kiwmi_view.c b/kiwmi/luak/kiwmi_view.c index f5222ad..84f9f4c 100644 --- a/kiwmi/luak/kiwmi_view.c +++ b/kiwmi/luak/kiwmi_view.c @@ -15,6 +15,7 @@ #include #include +#include "desktop/desktop_surface.h" #include "desktop/output.h" #include "desktop/view.h" #include "desktop/xdg_shell.h" @@ -120,7 +121,11 @@ l_kiwmi_view_hidden(lua_State *L) struct kiwmi_view *view = obj->object; - lua_pushboolean(L, view->hidden); + int lx, ly; // unused + bool enabled = + wlr_scene_node_coords(&view->desktop_surface.tree->node, &lx, &ly); + + lua_pushboolean(L, !enabled); return 1; } @@ -275,8 +280,11 @@ l_kiwmi_view_pos(lua_State *L) struct kiwmi_view *view = obj->object; - lua_pushinteger(L, view->x); - lua_pushinteger(L, view->y); + int lx, ly; + desktop_surface_get_pos(&view->desktop_surface, &lx, &ly); + + lua_pushinteger(L, lx); + lua_pushinteger(L, ly); return 2; } diff --git a/kiwmi/meson.build b/kiwmi/meson.build index ceb2471..d05e559 100644 --- a/kiwmi/meson.build +++ b/kiwmi/meson.build @@ -3,6 +3,7 @@ kiwmi_sources = files( 'server.c', 'color.c', 'desktop/desktop.c', + 'desktop/desktop_surface.c', 'desktop/layer_shell.c', 'desktop/output.c', 'desktop/popup.c',