Prefer wlr_scene as the source of truth

Use it for getting the surface under cursor, position of surfaces, etc.
This commit is contained in:
tiosgz 2022-05-08 09:42:33 +00:00
parent d5940c396c
commit 24cc0719a4
12 changed files with 216 additions and 181 deletions

View file

@ -8,6 +8,9 @@
#ifndef KIWMI_DESKTOP_DESKTOP_SURFACE_H #ifndef KIWMI_DESKTOP_DESKTOP_SURFACE_H
#define KIWMI_DESKTOP_DESKTOP_SURFACE_H #define KIWMI_DESKTOP_DESKTOP_SURFACE_H
struct wlr_surface;
struct kiwmi_desktop;
enum kiwmi_desktop_surface_type { enum kiwmi_desktop_surface_type {
KIWMI_DESKTOP_SURFACE_VIEW, KIWMI_DESKTOP_SURFACE_VIEW,
KIWMI_DESKTOP_SURFACE_LAYER, KIWMI_DESKTOP_SURFACE_LAYER,
@ -22,6 +25,21 @@ struct kiwmi_desktop_surface {
struct wlr_scene_tree *popups_tree; struct wlr_scene_tree *popups_tree;
enum kiwmi_desktop_surface_type type; 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 */ #endif /* KIWMI_DESKTOP_DESKTOP_SURFACE_H */

View file

@ -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_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_tiled(struct kiwmi_view *view, enum wlr_edges edges);
void view_set_hidden(struct kiwmi_view *view, bool hidden); 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); void view_focus(struct kiwmi_view *view);
struct kiwmi_view *view_at( struct kiwmi_view *view_at(struct kiwmi_desktop *desktop, double lx, double ly);
struct kiwmi_desktop *desktop,
double lx,
double ly,
struct wlr_surface **surface,
double *sx,
double *sy);
void view_move(struct kiwmi_view *view); void view_move(struct kiwmi_view *view);
void view_resize(struct kiwmi_view *view, uint32_t edges); void view_resize(struct kiwmi_view *view, uint32_t edges);
struct kiwmi_view *view_create( struct kiwmi_view *view_create(

View file

@ -22,6 +22,7 @@
#include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "desktop/desktop_surface.h"
#include "desktop/layer_shell.h" #include "desktop/layer_shell.h"
#include "desktop/output.h" #include "desktop/output.h"
#include "desktop/stratum.h" #include "desktop/stratum.h"
@ -29,6 +30,7 @@
#include "desktop/xdg_shell.h" #include "desktop/xdg_shell.h"
#include "input/cursor.h" #include "input/cursor.h"
#include "input/input.h" #include "input/input.h"
#include "input/seat.h"
#include "server.h" #include "server.h"
bool bool
@ -127,19 +129,14 @@ desktop_active_output(struct kiwmi_server *server)
return output; return output;
} }
// 2. focused view center // 2. focused view
if (!wl_list_empty(&server->desktop.views)) { struct kiwmi_view *focused_view = server->input.seat->focused_view;
struct kiwmi_view *view; if (focused_view) {
wl_list_for_each (view, &server->desktop.views, link) { output = desktop_surface_get_output(&focused_view->desktop_surface);
break; // get first element of list
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 // 3. cursor

View file

@ -0,0 +1,87 @@
/* Copyright (c), Charlotte Meyer <dev@buffet.sh>
*
* 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 <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_xdg_shell.h>
#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);
}

View file

@ -390,6 +390,18 @@ layer_at(
return NULL; 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 void
layer_shell_new_surface_notify(struct wl_listener *listener, void *data) 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->layer = layer_surface->current.layer;
layer->desktop_surface.type = KIWMI_DESKTOP_SURFACE_LAYER; layer->desktop_surface.type = KIWMI_DESKTOP_SURFACE_LAYER;
layer->desktop_surface.impl = &layer_desktop_surface_impl;
layer->destroy.notify = kiwmi_layer_destroy_notify; layer->destroy.notify = kiwmi_layer_destroy_notify;
wl_signal_add(&layer_surface->events.destroy, &layer->destroy); wl_signal_add(&layer_surface->events.destroy, &layer->destroy);

View file

@ -8,6 +8,7 @@
#include "desktop/view.h" #include "desktop/view.h"
#include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "desktop/output.h" #include "desktop/output.h"
@ -104,19 +105,15 @@ 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.tree->node, x, y);
wlr_scene_node_set_position(&view->desktop_surface.popups_tree->node, x, y); wlr_scene_node_set_position(&view->desktop_surface.popups_tree->node, x, y);
struct kiwmi_view_child *child; int lx, ly; // unused
wl_list_for_each (child, &view->children, link) { // If it is enabled (as well as all its parents)
if (child->impl && child->impl->reconfigure) { if (wlr_scene_node_coords(&view->desktop_surface.tree->node, &lx, &ly)) {
child->impl->reconfigure(child); 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 void
view_set_tiled(struct kiwmi_view *view, enum wlr_edges edges) view_set_tiled(struct kiwmi_view *view, enum wlr_edges edges)
{ {
@ -139,71 +136,22 @@ view_set_hidden(struct kiwmi_view *view, bool hidden)
&view->desktop_surface.popups_tree->node, !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 * struct kiwmi_view *
view_at( view_at(struct kiwmi_desktop *desktop, double lx, double ly)
struct kiwmi_desktop *desktop,
double lx,
double ly,
struct wlr_surface **surface,
double *sx,
double *sy)
{ {
struct kiwmi_view *view; struct kiwmi_desktop_surface *desktop_surface =
wl_list_for_each (view, &desktop->views, link) { desktop_surface_at(desktop, lx, ly);
if (view->hidden || !view->mapped) {
continue;
}
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 static void
view_begin_interactive( view_begin_interactive(
struct kiwmi_view *view, struct kiwmi_view *view,
@ -228,17 +176,20 @@ view_begin_interactive(
cursor->cursor_mode = mode; cursor->cursor_mode = mode;
cursor->grabbed.view = view; 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) { if (mode == KIWMI_CURSOR_MOVE) {
cursor->grabbed.orig_x = cursor->cursor->x - view->x; cursor->grabbed.orig_x = cursor->cursor->x - view_lx;
cursor->grabbed.orig_y = cursor->cursor->y - view->y; cursor->grabbed.orig_y = cursor->cursor->y - view_ly;
} else { } else {
cursor->grabbed.orig_x = cursor->cursor->x; cursor->grabbed.orig_x = cursor->cursor->x;
cursor->grabbed.orig_y = cursor->cursor->y; cursor->grabbed.orig_y = cursor->cursor->y;
cursor->grabbed.resize_edges = edges; cursor->grabbed.resize_edges = edges;
} }
cursor->grabbed.orig_geom.x = view->x; cursor->grabbed.orig_geom.x = view_lx;
cursor->grabbed.orig_geom.y = view->y; cursor->grabbed.orig_geom.y = view_ly;
cursor->grabbed.orig_geom.width = width; cursor->grabbed.orig_geom.width = width;
cursor->grabbed.orig_geom.height = height; 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 * struct kiwmi_view *
view_create( view_create(
struct kiwmi_desktop *desktop, struct kiwmi_desktop *desktop,
@ -305,6 +287,7 @@ view_create(
wl_list_init(&view->children); wl_list_init(&view->children);
view->desktop_surface.type = KIWMI_DESKTOP_SURFACE_VIEW; 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.unmap);
wl_signal_init(&view->events.request_move); wl_signal_init(&view->events.request_move);

View file

@ -181,20 +181,21 @@ xdg_surface_unmap_notify(struct wl_listener *listener, void *UNUSED(data))
{ {
struct kiwmi_view *view = wl_container_of(listener, view, unmap); 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.tree->node, false);
wlr_scene_node_set_enabled( wlr_scene_node_set_enabled(
&view->desktop_surface.popups_tree->node, false); &view->desktop_surface.popups_tree->node, false);
struct kiwmi_desktop *desktop = view->desktop; struct kiwmi_server *server =
struct kiwmi_server *server = wl_container_of(desktop, server, desktop); wl_container_of(view->desktop, server, desktop);
cursor_refresh_focus(server->input.cursor, NULL, NULL, NULL); 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 static void
xdg_surface_commit_notify(struct wl_listener *listener, void *UNUSED(data)) xdg_surface_commit_notify(struct wl_listener *listener, void *UNUSED(data))

View file

@ -14,6 +14,7 @@
#include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_pointer.h> #include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_seat.h> #include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
@ -284,72 +285,24 @@ cursor_refresh_focus(
struct kiwmi_desktop *desktop = &cursor->server->desktop; struct kiwmi_desktop *desktop = &cursor->server->desktop;
struct wlr_seat *seat = cursor->server->input.seat->seat; 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; struct wlr_surface *surface = NULL;
double sx; double sx;
double sy; double sy;
struct kiwmi_layer *layer = layer_at( struct wlr_scene_node *node_at = wlr_scene_node_at(
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &desktop->scene->node, cursor->cursor->x, cursor->cursor->y, &sx, &sy);
&surface,
ox,
oy,
&sx,
&sy);
struct kiwmi_view *view;
if (!layer) { if (node_at && node_at->type == WLR_SCENE_NODE_SURFACE) {
layer = layer_at( struct wlr_scene_surface *scene_surface =
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], wlr_scene_surface_from_node(node_at);
&surface, surface = scene_surface->surface;
ox,
oy, if (surface != seat->pointer_state.focused_surface) {
&sx, wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
&sy);
} }
} else {
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) {
wlr_xcursor_manager_set_cursor_image( wlr_xcursor_manager_set_cursor_image(
cursor->xcursor_manager, "left_ptr", cursor->cursor); 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); wlr_seat_pointer_clear_focus(seat);
} }

View file

@ -73,17 +73,8 @@ l_kiwmi_cursor_view_at_pos(lua_State *L)
struct kiwmi_cursor *cursor = obj->object; struct kiwmi_cursor *cursor = obj->object;
struct kiwmi_server *server = cursor->server; struct kiwmi_server *server = cursor->server;
struct wlr_surface *surface; struct kiwmi_view *view =
double sx; view_at(&server->desktop, cursor->cursor->x, cursor->cursor->y);
double sy;
struct kiwmi_view *view = view_at(
&server->desktop,
cursor->cursor->x,
cursor->cursor->y,
&surface,
&sx,
&sy);
if (view) { if (view) {
lua_pushcfunction(L, luaK_kiwmi_view_new); lua_pushcfunction(L, luaK_kiwmi_view_new);

View file

@ -313,12 +313,7 @@ l_kiwmi_server_view_at(lua_State *L)
double lx = lua_tonumber(L, 2); double lx = lua_tonumber(L, 2);
double ly = lua_tonumber(L, 3); double ly = lua_tonumber(L, 3);
struct wlr_surface *surface; struct kiwmi_view *view = view_at(&server->desktop, lx, ly);
double sx;
double sy;
struct kiwmi_view *view =
view_at(&server->desktop, lx, ly, &surface, &sx, &sy);
if (view) { if (view) {
lua_pushcfunction(L, luaK_kiwmi_view_new); lua_pushcfunction(L, luaK_kiwmi_view_new);

View file

@ -15,6 +15,7 @@
#include <wlr/util/edges.h> #include <wlr/util/edges.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "desktop/desktop_surface.h"
#include "desktop/output.h" #include "desktop/output.h"
#include "desktop/view.h" #include "desktop/view.h"
#include "desktop/xdg_shell.h" #include "desktop/xdg_shell.h"
@ -120,7 +121,11 @@ l_kiwmi_view_hidden(lua_State *L)
struct kiwmi_view *view = obj->object; 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; return 1;
} }
@ -275,8 +280,11 @@ l_kiwmi_view_pos(lua_State *L)
struct kiwmi_view *view = obj->object; struct kiwmi_view *view = obj->object;
lua_pushinteger(L, view->x); int lx, ly;
lua_pushinteger(L, view->y); desktop_surface_get_pos(&view->desktop_surface, &lx, &ly);
lua_pushinteger(L, lx);
lua_pushinteger(L, ly);
return 2; return 2;
} }

View file

@ -3,6 +3,7 @@ kiwmi_sources = files(
'server.c', 'server.c',
'color.c', 'color.c',
'desktop/desktop.c', 'desktop/desktop.c',
'desktop/desktop_surface.c',
'desktop/layer_shell.c', 'desktop/layer_shell.c',
'desktop/output.c', 'desktop/output.c',
'desktop/popup.c', 'desktop/popup.c',