diff --git a/include/desktop/desktop.h b/include/desktop/desktop.h index 6fbdd35..9247219 100644 --- a/include/desktop/desktop.h +++ b/include/desktop/desktop.h @@ -9,23 +9,32 @@ #define KIWMI_DESKTOP_DESKTOP_H #include +#include + +#include "desktop/stratum.h" struct kiwmi_desktop { struct wlr_compositor *compositor; + struct wlr_xdg_shell *xdg_shell; struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager; struct wlr_layer_shell_v1 *layer_shell; + struct wlr_data_device_manager *data_device_manager; + struct wlr_output_layout *output_layout; struct wl_list outputs; // struct kiwmi_output::link struct wl_list views; // struct kiwmi_view::link - float bg_color[4]; + struct wlr_scene *scene; + struct wlr_scene_rect *background_rect; + struct wlr_scene_tree *strata[KIWMI_STRATA_COUNT]; struct wl_listener xdg_shell_new_surface; struct wl_listener xdg_toplevel_new_decoration; struct wl_listener layer_shell_new_surface; struct wl_listener new_output; + struct wl_listener output_layout_change; struct { struct wl_signal new_output; diff --git a/include/desktop/desktop_surface.h b/include/desktop/desktop_surface.h new file mode 100644 index 0000000..d0de3ab --- /dev/null +++ b/include/desktop/desktop_surface.h @@ -0,0 +1,45 @@ +/* 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/. + */ + +#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, +}; + +struct kiwmi_desktop_surface { + // The tree is where the config is supposed to put custom decorations (it + // also contains the surface_node) + struct wlr_scene_tree *tree; + struct wlr_scene_node *surface_node; + + 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/layer_shell.h b/include/desktop/layer_shell.h index 837275e..f17bfd9 100644 --- a/include/desktop/layer_shell.h +++ b/include/desktop/layer_shell.h @@ -14,12 +14,15 @@ #include #include +#include "desktop/desktop_surface.h" #include "desktop/output.h" struct kiwmi_layer { struct wl_list link; + struct kiwmi_desktop_surface desktop_surface; + struct wlr_layer_surface_v1 *layer_surface; - uint32_t layer; + uint32_t layer; // enum zwlr_layer_shell_v1_layer struct kiwmi_output *output; @@ -27,19 +30,10 @@ struct kiwmi_layer { struct wl_listener commit; struct wl_listener map; struct wl_listener unmap; - - struct wlr_box geom; }; void arrange_layers(struct kiwmi_output *output); -struct kiwmi_layer *layer_at( - struct wl_list *layers, - struct wlr_surface **surface, - double ox, - double oy, - double *sx, - double *sy); void layer_shell_new_surface_notify(struct wl_listener *listener, void *data); #endif /* KIWMI_DESKTOP_LAYER_SHELL_H */ diff --git a/include/desktop/output.h b/include/desktop/output.h index 3f8c034..bf96fc6 100644 --- a/include/desktop/output.h +++ b/include/desktop/output.h @@ -11,19 +11,22 @@ #include #include +#include "desktop/stratum.h" + struct kiwmi_output { struct wl_list link; struct kiwmi_desktop *desktop; struct wlr_output *wlr_output; + struct wl_listener frame; struct wl_listener commit; struct wl_listener destroy; struct wl_listener mode; - struct wl_list layers[4]; // struct kiwmi_layer_surface::link - struct wlr_box usable_area; + struct wl_list layers[4]; // struct kiwmi_layer::link + struct wlr_scene_tree *strata[KIWMI_STRATA_COUNT]; - int damaged; + struct wlr_box usable_area; struct { struct wl_signal destroy; @@ -42,7 +45,6 @@ struct kiwmi_render_data { }; void new_output_notify(struct wl_listener *listener, void *data); - -void output_damage(struct kiwmi_output *output); +void output_layout_change_notify(struct wl_listener *listener, void *data); #endif /* KIWMI_DESKTOP_OUTPUT_H */ diff --git a/include/desktop/popup.h b/include/desktop/popup.h new file mode 100644 index 0000000..78ec98a --- /dev/null +++ b/include/desktop/popup.h @@ -0,0 +1,20 @@ +/* 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/. + */ + +#ifndef KIWMI_DESKTOP_POPUP_H +#define KIWMI_DESKTOP_POPUP_H + +struct wlr_xdg_popup; +struct kiwmi_desktop_surface; + +struct kiwmi_desktop_surface * +popup_get_desktop_surface(struct wlr_xdg_popup *popup); +void popup_attach( + struct wlr_xdg_popup *popup, + struct kiwmi_desktop_surface *desktop_surface); + +#endif /* KIWMI_DESKTOP_POPUP_H */ diff --git a/include/desktop/stratum.h b/include/desktop/stratum.h new file mode 100644 index 0000000..33ad252 --- /dev/null +++ b/include/desktop/stratum.h @@ -0,0 +1,33 @@ +/* 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/. + */ + +#ifndef KIWMI_DESKTOP_STRATUM_H +#define KIWMI_DESKTOP_STRATUM_H + +#include + +/** + * A stratum is a layer in the scene-graph (the name was chosen to avoid + * confusion with layer-shell). The root node contains a scene_tree for each + * stratum, which itself contains a scene_tree per output. + */ + +// There are some assumptions made about the values, don't mindlessly change. +enum kiwmi_stratum { + KIWMI_STRATUM_LS_BACKGROUND, // LS == layer_shell + KIWMI_STRATUM_LS_BOTTOM, + KIWMI_STRATUM_NORMAL, + KIWMI_STRATUM_LS_TOP, + KIWMI_STRATUM_LS_OVERLAY, + KIWMI_STRATUM_POPUPS, + KIWMI_STRATA_COUNT, + KIWMI_STRATUM_NONE = KIWMI_STRATA_COUNT, +}; + +enum kiwmi_stratum stratum_from_layer_shell_layer(uint32_t layer); + +#endif /* KIWMI_DESKTOP_STRATUM_H */ diff --git a/include/desktop/view.h b/include/desktop/view.h index 3055304..5ada1bb 100644 --- a/include/desktop/view.h +++ b/include/desktop/view.h @@ -17,6 +17,8 @@ #include #include +#include "desktop/desktop_surface.h" + enum kiwmi_view_prop { KIWMI_VIEW_PROP_APP_ID, KIWMI_VIEW_PROP_TITLE, @@ -28,7 +30,7 @@ enum kiwmi_view_type { struct kiwmi_view { struct wl_list link; - struct wl_list children; // struct kiwmi_view_child::link + struct kiwmi_desktop_surface desktop_surface; struct kiwmi_desktop *desktop; @@ -47,16 +49,10 @@ struct kiwmi_view { struct wl_listener unmap; struct wl_listener commit; struct wl_listener destroy; - struct wl_listener new_popup; - struct wl_listener new_subsurface; struct wl_listener request_move; struct wl_listener request_resize; - int x; - int y; - bool mapped; - bool hidden; struct { struct wl_signal unmap; @@ -71,58 +67,12 @@ struct kiwmi_view { struct kiwmi_view_impl { void (*close)(struct kiwmi_view *view); - void (*for_each_surface)( - struct kiwmi_view *view, - wlr_surface_iterator_func_t callback, - void *user_data); pid_t (*get_pid)(struct kiwmi_view *view); void (*set_activated)(struct kiwmi_view *view, bool activated); void (*set_size)(struct kiwmi_view *view, uint32_t width, uint32_t height); const char *( *get_string_prop)(struct kiwmi_view *view, enum kiwmi_view_prop prop); void (*set_tiled)(struct kiwmi_view *view, enum wlr_edges edges); - struct wlr_surface *(*surface_at)( - struct kiwmi_view *view, - double sx, - double sy, - double *sub_x, - double *sub_y); -}; - -enum kiwmi_view_child_type { - KIWMI_VIEW_CHILD_SUBSURFACE, - KIWMI_VIEW_CHILD_XDG_POPUP, -}; - -struct kiwmi_view_child { - struct wl_list link; - struct wl_list children; // struct kiwmi_view_child::link - - struct kiwmi_view *view; - struct kiwmi_view_child *parent; - - enum kiwmi_view_child_type type; - const struct kiwmi_view_child_impl *impl; - - struct wlr_surface *wlr_surface; - union { - struct wlr_subsurface *wlr_subsurface; - struct wlr_xdg_popup *wlr_xdg_popup; - }; - - bool mapped; - - struct wl_listener commit; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener new_popup; - struct wl_listener new_subsurface; - struct wl_listener extension_destroy; // the union'ed object destroy - struct wl_listener surface_destroy; // wlr_surface::events.destroy -}; - -struct kiwmi_view_child_impl { - void (*reconfigure)(struct kiwmi_view_child *child); }; struct kiwmi_request_resize_event { @@ -131,10 +81,6 @@ struct kiwmi_request_resize_event { }; void view_close(struct kiwmi_view *view); -void view_for_each_surface( - struct kiwmi_view *view, - wlr_surface_iterator_func_t callback, - void *user_data); pid_t view_get_pid(struct kiwmi_view *view); void view_get_size(struct kiwmi_view *view, uint32_t *width, uint32_t *height); const char *view_get_app_id(struct kiwmi_view *view); @@ -143,21 +89,10 @@ void view_set_activated(struct kiwmi_view *view, bool activated); 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); -struct wlr_surface *view_surface_at( - struct kiwmi_view *view, - double sx, - double sy, - double *sub_x, - double *sub_y); +void view_set_hidden(struct kiwmi_view *view, bool hidden); 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( @@ -165,20 +100,4 @@ struct kiwmi_view *view_create( enum kiwmi_view_type type, const struct kiwmi_view_impl *impl); -void -view_init_subsurfaces(struct kiwmi_view_child *child, struct kiwmi_view *view); -bool view_child_is_mapped(struct kiwmi_view_child *child); -void view_child_damage(struct kiwmi_view_child *child); -void view_child_destroy(struct kiwmi_view_child *child); -struct kiwmi_view_child *view_child_create( - struct kiwmi_view_child *parent, - struct kiwmi_view *view, - struct wlr_surface *wlr_surface, - enum kiwmi_view_child_type type, - const struct kiwmi_view_child_impl *impl); -struct kiwmi_view_child *view_child_subsurface_create( - struct kiwmi_view_child *parent, - struct kiwmi_view *view, - struct wlr_subsurface *subsurface); - #endif /* KIWMI_DESKTOP_VIEW_H */ diff --git a/include/luak/kiwmi_renderer.h b/include/luak/kiwmi_renderer.h deleted file mode 100644 index 5333fe2..0000000 --- a/include/luak/kiwmi_renderer.h +++ /dev/null @@ -1,16 +0,0 @@ -/* 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/. - */ - -#ifndef KIWMI_LUAK_KIWMI_RENDERER_H -#define KIWMI_LUAK_KIWMI_RENDERER_H - -#include - -int luaK_kiwmi_renderer_new(lua_State *L); -int luaK_kiwmi_renderer_register(lua_State *L); - -#endif /* KIWMI_LUAK_KIWMI_RENDERER_H */ diff --git a/kiwmi/desktop/desktop.c b/kiwmi/desktop/desktop.c index dd9dc83..7d1c1b8 100644 --- a/kiwmi/desktop/desktop.c +++ b/kiwmi/desktop/desktop.c @@ -17,16 +17,21 @@ #include #include #include +#include #include #include #include +#include +#include "desktop/desktop_surface.h" #include "desktop/layer_shell.h" #include "desktop/output.h" +#include "desktop/stratum.h" #include "desktop/view.h" #include "desktop/xdg_shell.h" #include "input/cursor.h" #include "input/input.h" +#include "input/seat.h" #include "server.h" bool @@ -44,10 +49,28 @@ desktop_init(struct kiwmi_desktop *desktop) wlr_xdg_output_manager_v1_create( server->wl_display, desktop->output_layout); - desktop->bg_color[0] = 0.1f; - desktop->bg_color[1] = 0.1f; - desktop->bg_color[2] = 0.1f; - desktop->bg_color[3] = 1.0f; + desktop->scene = wlr_scene_create(); + if (!desktop->scene) { + wlr_log(WLR_ERROR, "failed to create scene"); + return false; + } + + const float bg_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + desktop->background_rect = + wlr_scene_rect_create(&desktop->scene->node, 0, 0, bg_color); + // No point in showing black + wlr_scene_node_set_enabled(&desktop->background_rect->node, false); + + // Create a scene-graph tree for each stratum + for (size_t i = 0; i < KIWMI_STRATA_COUNT; ++i) { + desktop->strata[i] = wlr_scene_tree_create(&desktop->scene->node); + } + + wlr_scene_attach_output_layout(desktop->scene, desktop->output_layout); + + struct wlr_presentation *presentation = + wlr_presentation_create(server->wl_display, server->backend); + wlr_scene_set_presentation(desktop->scene, presentation); desktop->xdg_shell = wlr_xdg_shell_create(server->wl_display); desktop->xdg_shell_new_surface.notify = xdg_shell_new_surface_notify; @@ -75,6 +98,10 @@ desktop_init(struct kiwmi_desktop *desktop) desktop->new_output.notify = new_output_notify; wl_signal_add(&server->backend->events.new_output, &desktop->new_output); + desktop->output_layout_change.notify = output_layout_change_notify; + wl_signal_add( + &desktop->output_layout->events.change, &desktop->output_layout_change); + wl_signal_init(&desktop->events.new_output); wl_signal_init(&desktop->events.view_map); wl_signal_init(&desktop->events.request_active_output); @@ -87,6 +114,8 @@ desktop_fini(struct kiwmi_desktop *desktop) { wlr_output_layout_destroy(desktop->output_layout); desktop->output_layout = NULL; + wlr_scene_node_destroy(&desktop->scene->node); + desktop->scene = NULL; } struct kiwmi_output * @@ -100,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 78e4a34..3b77a0c 100644 --- a/kiwmi/desktop/layer_shell.c +++ b/kiwmi/desktop/layer_shell.c @@ -15,7 +15,9 @@ #include #include "desktop/desktop.h" +#include "desktop/desktop_surface.h" #include "desktop/output.h" +#include "desktop/stratum.h" #include "input/seat.h" #include "server.h" @@ -24,12 +26,17 @@ kiwmi_layer_destroy_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_layer *layer = wl_container_of(listener, layer, destroy); - wl_list_remove(&layer->link); + wlr_scene_node_destroy(&layer->desktop_surface.tree->node); + wlr_scene_node_destroy(&layer->desktop_surface.popups_tree->node); + wl_list_remove(&layer->destroy.link); wl_list_remove(&layer->map.link); wl_list_remove(&layer->unmap.link); - arrange_layers(layer->output); + if (layer->output != NULL) { + wl_list_remove(&layer->link); + arrange_layers(layer->output); + } free(layer); } @@ -40,25 +47,21 @@ kiwmi_layer_commit_notify(struct wl_listener *listener, void *UNUSED(data)) struct kiwmi_layer *layer = wl_container_of(listener, layer, commit); struct kiwmi_output *output = layer->output; - struct wlr_box old_geom = layer->geom; - - if (layer->layer_surface->current.committed != 0) { - arrange_layers(output); - } - - bool layer_changed = layer->layer != layer->layer_surface->current.layer; - bool geom_changed = memcmp(&old_geom, &layer->geom, sizeof(old_geom)) != 0; - bool buffer_changed = pixman_region32_not_empty( - &layer->layer_surface->surface->buffer_damage); - - if (layer_changed) { + if (layer->layer != layer->layer_surface->current.layer) { wl_list_remove(&layer->link); layer->layer = layer->layer_surface->current.layer; wl_list_insert(&output->layers[layer->layer], &layer->link); + + enum kiwmi_stratum new_stratum = + stratum_from_layer_shell_layer(layer->layer); + + wlr_scene_node_reparent( + &layer->desktop_surface.tree->node, + &output->strata[new_stratum]->node); } - if (buffer_changed || layer_changed || geom_changed) { - output_damage(layer->output); + if (layer->layer_surface->current.committed != 0) { + arrange_layers(output); } } @@ -67,7 +70,10 @@ kiwmi_layer_map_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_layer *layer = wl_container_of(listener, layer, map); - output_damage(layer->output); + wlr_scene_node_set_enabled(&layer->desktop_surface.tree->node, true); + wlr_scene_node_set_enabled(&layer->desktop_surface.popups_tree->node, true); + + arrange_layers(layer->output); } static void @@ -75,7 +81,11 @@ kiwmi_layer_unmap_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_layer *layer = wl_container_of(listener, layer, unmap); - output_damage(layer->output); + wlr_scene_node_set_enabled(&layer->desktop_surface.tree->node, false); + wlr_scene_node_set_enabled( + &layer->desktop_surface.popups_tree->node, false); + + arrange_layers(layer->output); } static void @@ -241,7 +251,14 @@ arrange_layer( continue; } - layer->geom = arranged_area; + wlr_scene_node_set_position( + &layer->desktop_surface.tree->node, + arranged_area.x, + arranged_area.y); + wlr_scene_node_set_position( + &layer->desktop_surface.popups_tree->node, + arranged_area.x, + arranged_area.y); apply_exclusive( usable_area, @@ -343,36 +360,18 @@ arrange_layers(struct kiwmi_output *output) seat_focus_layer(seat, topmost); } -struct kiwmi_layer * -layer_at( - struct wl_list *layers, - struct wlr_surface **surface, - double ox, - double oy, - double *sx, - double *sy) +static struct kiwmi_output * +layer_desktop_surface_get_output(struct kiwmi_desktop_surface *desktop_surface) { - struct kiwmi_layer *layer; - wl_list_for_each_reverse (layer, layers, link) { - double layer_sx = ox - layer->geom.x; - double layer_sy = oy - layer->geom.y; - - double _sx; - double _sy; - struct wlr_surface *_surface = wlr_layer_surface_v1_surface_at( - layer->layer_surface, layer_sx, layer_sy, &_sx, &_sy); - - if (_surface) { - *sx = _sx; - *sy = _sy; - *surface = _surface; - return layer; - } - } - - return NULL; + 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) { @@ -413,6 +412,9 @@ layer_shell_new_surface_notify(struct wl_listener *listener, void *data) layer->output = output; 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); @@ -425,10 +427,25 @@ layer_shell_new_surface_notify(struct wl_listener *listener, void *data) layer->unmap.notify = kiwmi_layer_unmap_notify; wl_signal_add(&layer_surface->events.unmap, &layer->unmap); + layer_surface->data = layer; + + enum kiwmi_stratum stratum = stratum_from_layer_shell_layer(layer->layer); + + layer->desktop_surface.tree = + wlr_scene_tree_create(&output->strata[stratum]->node); + layer->desktop_surface.popups_tree = + wlr_scene_tree_create(&output->strata[KIWMI_STRATUM_POPUPS]->node); + layer->desktop_surface.surface_node = wlr_scene_subsurface_tree_create( + &layer->desktop_surface.tree->node, layer->layer_surface->surface); + + wlr_scene_node_set_enabled(&layer->desktop_surface.tree->node, false); + wlr_scene_node_set_enabled( + &layer->desktop_surface.popups_tree->node, false); + wl_list_insert(&output->layers[layer->layer], &layer->link); // Temporarily set the layer's current state to pending - // So that we can easily arrange it + // so that we can easily arrange it struct wlr_layer_surface_v1_state old_state = layer_surface->current; layer_surface->current = layer_surface->pending; arrange_layers(output); diff --git a/kiwmi/desktop/output.c b/kiwmi/desktop/output.c index eeb62f3..3c38788 100644 --- a/kiwmi/desktop/output.c +++ b/kiwmi/desktop/output.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -30,216 +31,24 @@ #include "input/pointer.h" #include "server.h" -static void -render_layer_surface(struct wlr_surface *surface, int x, int y, void *data) -{ - struct kiwmi_render_data *rdata = data; - struct wlr_output *wlr_output = rdata->output; - struct wlr_box *geom = rdata->data; - - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (!texture) { - return; - } - - int ox = x + geom->x; - int oy = y + geom->y; - - struct wlr_box box = { - .x = ox * wlr_output->scale, - .y = oy * wlr_output->scale, - .width = surface->current.width * wlr_output->scale, - .height = surface->current.height * wlr_output->scale, - }; - - float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box( - matrix, &box, transform, 0, wlr_output->transform_matrix); - - wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1); - - wlr_surface_send_frame_done(surface, rdata->when); -} - -static void -render_layer(struct wl_list *layer, struct kiwmi_render_data *rdata) -{ - struct kiwmi_layer *surface; - wl_list_for_each (surface, layer, link) { - rdata->data = &surface->geom; - - wlr_layer_surface_v1_for_each_surface( - surface->layer_surface, render_layer_surface, rdata); - } -} - -static void -send_frame_done_to_layer_surface( - struct wlr_surface *surface, - int UNUSED(x), - int UNUSED(y), - void *data) -{ - struct timespec *now = data; - wlr_surface_send_frame_done(surface, now); -} - -static void -send_frame_done_to_layer(struct wl_list *layer, struct timespec *now) -{ - struct kiwmi_layer *surface; - wl_list_for_each (surface, layer, link) { - wlr_layer_surface_v1_for_each_surface( - surface->layer_surface, send_frame_done_to_layer_surface, now); - } -} - -static void -render_surface(struct wlr_surface *surface, int sx, int sy, void *data) -{ - struct kiwmi_render_data *rdata = data; - struct kiwmi_view *view = rdata->data; - struct wlr_output *wlr_output = rdata->output; - - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (!texture) { - return; - } - - int ox = rdata->output_lx + sx + view->x - view->geom.x; - int oy = rdata->output_ly + sy + view->y - view->geom.y; - - struct wlr_box box = { - .x = ox * wlr_output->scale, - .y = oy * wlr_output->scale, - .width = surface->current.width * wlr_output->scale, - .height = surface->current.height * wlr_output->scale, - }; - - float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box( - matrix, &box, transform, 0, wlr_output->transform_matrix); - - wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1); - - wlr_surface_send_frame_done(surface, rdata->when); -} - -static void -send_frame_done_to_surface( - struct wlr_surface *surface, - int UNUSED(sx), - int UNUSED(sy), - void *data) -{ - struct timespec *now = data; - wlr_surface_send_frame_done(surface, now); -} - -static bool -render_cursors(struct wlr_output *wlr_output) -{ - pixman_region32_t damage; - pixman_region32_init(&damage); - wlr_output_render_software_cursors(wlr_output, &damage); - bool damaged = pixman_region32_not_empty(&damage); - pixman_region32_fini(&damage); - - return damaged; -} - static void output_frame_notify(struct wl_listener *listener, void *data) { struct kiwmi_output *output = wl_container_of(listener, output, frame); struct wlr_output *wlr_output = data; - struct kiwmi_desktop *desktop = output->desktop; + + struct wlr_scene_output *scene_output = + wlr_scene_get_scene_output(output->desktop->scene, wlr_output); + + if (!scene_output) { + return; + } + + wlr_scene_output_commit(scene_output); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - - int buffer_age; - if (!wlr_output_attach_render(wlr_output, &buffer_age)) { - wlr_log(WLR_ERROR, "Failed to attach renderer to output"); - return; - } - - if (output->damaged == 0 && buffer_age > 0) { - send_frame_done_to_layer( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &now); - send_frame_done_to_layer( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now); - send_frame_done_to_layer( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &now); - send_frame_done_to_layer( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &now); - - struct kiwmi_view *view; - wl_list_for_each (view, &desktop->views, link) { - view_for_each_surface(view, send_frame_done_to_surface, &now); - } - - if (render_cursors(wlr_output)) { - output_damage(output); - } - - wlr_output_commit(wlr_output); - return; - } - - struct wlr_output_layout *output_layout = desktop->output_layout; - struct kiwmi_server *server = wl_container_of(desktop, server, desktop); - struct wlr_renderer *renderer = server->renderer; - - wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); - wlr_renderer_clear(renderer, desktop->bg_color); - - double output_lx = 0; - double output_ly = 0; - wlr_output_layout_output_coords( - output_layout, wlr_output, &output_lx, &output_ly); - - struct kiwmi_render_data rdata = { - .output = output->wlr_output, - .output_lx = output_lx, - .output_ly = output_ly, - .renderer = renderer, - .when = &now, - }; - - render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &rdata); - render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &rdata); - - struct kiwmi_view *view; - wl_list_for_each_reverse (view, &desktop->views, link) { - if (view->hidden || !view->mapped) { - continue; - } - - rdata.data = view; - - wl_signal_emit(&view->events.pre_render, &rdata); - view_for_each_surface(view, render_surface, &rdata); - wl_signal_emit(&view->events.post_render, &rdata); - } - - render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &rdata); - render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &rdata); - - bool damaged = render_cursors(wlr_output); - wlr_renderer_end(renderer); - - if (damaged) { - output_damage(output); - } else { - --output->damaged; - } - - wlr_output_commit(wlr_output); + wlr_scene_output_send_frame_done(scene_output, &now); } static void @@ -250,7 +59,6 @@ output_commit_notify(struct wl_listener *listener, void *data) if (event->committed & WLR_OUTPUT_STATE_TRANSFORM) { arrange_layers(output); - output_damage(output); wl_signal_emit(&output->events.resize, output); } @@ -261,13 +69,32 @@ output_destroy_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_output *output = wl_container_of(listener, output, destroy); + wl_signal_emit(&output->events.destroy, output); + + int n_layers = sizeof(output->layers) / sizeof(output->layers[0]); + for (int i = 0; i < n_layers; i++) { + struct kiwmi_layer *layer; + struct kiwmi_layer *tmp; + wl_list_for_each_safe (layer, tmp, &output->layers[i], link) { + // Set output to NULL to avoid rearranging the remaining layers. + // Our impl requires that we remove the layer from the list. + layer->output = NULL; + wl_list_remove(&layer->link); + wlr_layer_surface_v1_destroy(layer->layer_surface); + } + } + + if (output->desktop->scene) { + for (size_t i = 0; i < KIWMI_STRATA_COUNT; ++i) { + wlr_scene_node_destroy(&output->strata[i]->node); + } + } + if (output->desktop->output_layout) { wlr_output_layout_remove( output->desktop->output_layout, output->wlr_output); } - wl_signal_emit(&output->events.destroy, output); - wl_list_remove(&output->link); wl_list_remove(&output->frame.link); wl_list_remove(&output->commit.link); @@ -285,7 +112,6 @@ output_mode_notify(struct wl_listener *listener, void *UNUSED(data)) struct kiwmi_output *output = wl_container_of(listener, output, mode); arrange_layers(output); - output_damage(output); wl_signal_emit(&output->events.resize, output); } @@ -316,8 +142,6 @@ output_create(struct wlr_output *wlr_output, struct kiwmi_desktop *desktop) output->mode.notify = output_mode_notify; wl_signal_add(&wlr_output->events.mode, &output->mode); - output_damage(output); - return output; } @@ -369,20 +193,51 @@ new_output_notify(struct wl_listener *listener, void *data) wlr_output_create_global(wlr_output); - size_t len_outputs = sizeof(output->layers) / sizeof(output->layers[0]); - for (size_t i = 0; i < len_outputs; ++i) { + size_t len_layers = sizeof(output->layers) / sizeof(output->layers[0]); + for (size_t i = 0; i < len_layers; ++i) { wl_list_init(&output->layers[i]); } + for (size_t i = 0; i < KIWMI_STRATA_COUNT; ++i) { + output->strata[i] = wlr_scene_tree_create(&desktop->strata[i]->node); + } + wl_signal_init(&output->events.destroy); wl_signal_init(&output->events.resize); wl_signal_init(&output->events.usable_area_change); + wl_list_insert(&desktop->outputs, &output->link); + + wlr_output_layout_add_auto(desktop->output_layout, wlr_output); + wl_signal_emit(&desktop->events.new_output, output); } void -output_damage(struct kiwmi_output *output) +output_layout_change_notify(struct wl_listener *listener, void *UNUSED(data)) { - output->damaged = 2; + struct kiwmi_desktop *desktop = + wl_container_of(listener, desktop, output_layout_change); + + struct wlr_box *ol_box = + wlr_output_layout_get_box(desktop->output_layout, NULL); + wlr_scene_node_set_position( + &desktop->background_rect->node, ol_box->x, ol_box->y); + wlr_scene_rect_set_size( + desktop->background_rect, ol_box->width, ol_box->height); + + struct wlr_output_layout_output *ol_output; + wl_list_for_each (ol_output, &desktop->output_layout->outputs, link) { + struct kiwmi_output *output = ol_output->output->data; + + struct wlr_box *box = wlr_output_layout_get_box( + desktop->output_layout, output->wlr_output); + + for (size_t i = 0; i < KIWMI_STRATA_COUNT; ++i) { + if (output->strata[i]) { + wlr_scene_node_set_position( + &output->strata[i]->node, box->x, box->y); + } + } + } } diff --git a/kiwmi/desktop/popup.c b/kiwmi/desktop/popup.c new file mode 100644 index 0000000..9544b3c --- /dev/null +++ b/kiwmi/desktop/popup.c @@ -0,0 +1,119 @@ +/* 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/popup.h" + +#include +#include +#include +#include +#include + +#include "desktop/desktop.h" +#include "desktop/desktop_surface.h" +#include "desktop/layer_shell.h" +#include "desktop/output.h" +#include "desktop/view.h" + +struct kiwmi_desktop_surface * +popup_get_desktop_surface(struct wlr_xdg_popup *popup) +{ + struct wlr_surface *parent = popup->parent; + while (parent) { + if (wlr_surface_is_xdg_surface(parent)) { + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_from_wlr_surface(parent); + switch (xdg_surface->role) { + case WLR_XDG_SURFACE_ROLE_POPUP: + parent = xdg_surface->popup->parent; + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + struct kiwmi_view *view = xdg_surface->data; + return &view->desktop_surface; + default: + return NULL; + } + } else if (wlr_surface_is_layer_surface(parent)) { + struct wlr_layer_surface_v1 *layer_surface = + wlr_layer_surface_v1_from_wlr_surface(parent); + struct kiwmi_layer *layer = layer_surface->data; + return &layer->desktop_surface; + } else { + return NULL; + } + } + return NULL; +} + +static void +popup_unconstrain( + struct wlr_xdg_popup *popup, + struct kiwmi_desktop_surface *desktop_surface) +{ + struct kiwmi_output *output = desktop_surface_get_output(desktop_surface); + if (!output) { + return; + } + + struct wlr_output *wlr_output = output->wlr_output; + + int lx, ly; + desktop_surface_get_pos(desktop_surface, &lx, &ly); + + if (desktop_surface->type == KIWMI_DESKTOP_SURFACE_VIEW) { + // wlroots expects surface-local, not view-local coords + struct kiwmi_view *view = + wl_container_of(desktop_surface, view, desktop_surface); + lx -= view->geom.x; + ly -= view->geom.y; + } + + double ox = lx; + double oy = ly; + wlr_output_layout_output_coords( + output->desktop->output_layout, wlr_output, &ox, &oy); + + int output_width; + int output_height; + wlr_output_effective_resolution(wlr_output, &output_width, &output_height); + + // Relative to the desktop_surface + struct wlr_box output_box = { + .x = -ox, + .y = -oy, + .width = output_width, + .height = output_height, + }; + + wlr_xdg_popup_unconstrain_from_box(popup, &output_box); +} + +void +popup_attach( + struct wlr_xdg_popup *popup, + struct kiwmi_desktop_surface *desktop_surface) +{ + struct wlr_scene_tree *parent_tree = desktop_surface->popups_tree; + if (wlr_surface_is_xdg_surface(popup->parent)) { + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_from_wlr_surface(popup->parent); + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP + && xdg_surface->data) { + parent_tree = xdg_surface->data; + } + } + + popup_unconstrain(popup, desktop_surface); + + struct wlr_scene_node *node = + wlr_scene_xdg_surface_create(&parent_tree->node, popup->base); + if (!node) { + wlr_log(WLR_ERROR, "failed to attach popup to scene"); + return; + } + popup->base->data = node; +} diff --git a/kiwmi/desktop/stratum.c b/kiwmi/desktop/stratum.c new file mode 100644 index 0000000..dd9adc0 --- /dev/null +++ b/kiwmi/desktop/stratum.c @@ -0,0 +1,33 @@ +/* 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 + +#include + +#include "desktop/stratum.h" +#include "wlr-layer-shell-unstable-v1-protocol.h" + +enum kiwmi_stratum +stratum_from_layer_shell_layer(uint32_t layer) +{ + switch (layer) { + case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND: + return KIWMI_STRATUM_LS_BACKGROUND; + case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM: + return KIWMI_STRATUM_LS_BOTTOM; + case ZWLR_LAYER_SHELL_V1_LAYER_TOP: + return KIWMI_STRATUM_LS_TOP; + case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY: + return KIWMI_STRATUM_LS_OVERLAY; + default: + // We should update our codebase to support the layer + wlr_log( + WLR_ERROR, "No matching stratum for layer_shell layer %d", layer); + return KIWMI_STRATUM_NONE; + } +} diff --git a/kiwmi/desktop/view.c b/kiwmi/desktop/view.c index c741d8d..efd0d66 100644 --- a/kiwmi/desktop/view.c +++ b/kiwmi/desktop/view.c @@ -8,9 +8,11 @@ #include "desktop/view.h" #include +#include #include #include "desktop/output.h" +#include "desktop/stratum.h" #include "input/cursor.h" #include "input/seat.h" #include "server.h" @@ -23,17 +25,6 @@ view_close(struct kiwmi_view *view) } } -void -view_for_each_surface( - struct kiwmi_view *view, - wlr_surface_iterator_func_t callback, - void *user_data) -{ - if (view->impl->for_each_surface) { - view->impl->for_each_surface(view, callback, user_data); - } -} - pid_t view_get_pid(struct kiwmi_view *view) { @@ -84,42 +75,21 @@ view_set_size(struct kiwmi_view *view, uint32_t width, uint32_t height) { if (view->impl->set_size) { view->impl->set_size(view, width, height); - - struct kiwmi_view_child *child; - wl_list_for_each (child, &view->children, link) { - if (child->impl && child->impl->reconfigure) { - child->impl->reconfigure(child); - } - } - - struct kiwmi_output *output; - wl_list_for_each (output, &view->desktop->outputs, link) { - output_damage(output); - } } } void view_set_pos(struct kiwmi_view *view, uint32_t x, uint32_t y) { - view->x = x; - view->y = 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); - } - } - - 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); - - struct kiwmi_output *output; - wl_list_for_each (output, &desktop->outputs, link) { - output_damage(output); + 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); } } @@ -131,69 +101,39 @@ view_set_tiled(struct kiwmi_view *view, enum wlr_edges edges) } } -struct wlr_surface * -view_surface_at( - struct kiwmi_view *view, - double sx, - double sy, - double *sub_x, - double *sub_y) +void +view_set_hidden(struct kiwmi_view *view, bool hidden) { - if (view->impl->surface_at) { - return view->impl->surface_at(view, sx, sy, sub_x, sub_y); + if (!view->mapped) { + return; } - return NULL; -} + wlr_scene_node_set_enabled(&view->desktop_surface.tree->node, !hidden); + wlr_scene_node_set_enabled( + &view->desktop_surface.popups_tree->node, !hidden); -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; + struct kiwmi_server *server = + wl_container_of(view->desktop, server, desktop); + struct kiwmi_seat *seat = server->input.seat; + if (seat->focused_view == view) { + seat->focused_view = NULL; } - - 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 @@ -220,17 +160,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; } @@ -247,31 +190,37 @@ view_resize(struct kiwmi_view *view, uint32_t edges) view_begin_interactive(view, KIWMI_CURSOR_RESIZE, edges); } -/** - * Creates a kiwmi_view_child for each subsurface of either the 'child' or the - * 'view'. 'child' can be NULL, 'view' should never be. - */ -void -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 wlr_surface *surface = - child ? child->wlr_surface : view->wlr_surface; - if (!surface) { - wlr_log(WLR_ERROR, "Attempting to init_subsurfaces without a surface"); - return; + 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; } - struct wlr_subsurface *subsurface; - wl_list_for_each ( - subsurface, &surface->current.subsurfaces_below, current.link) { - view_child_subsurface_create(child, view, subsurface); - } - wl_list_for_each ( - subsurface, &surface->current.subsurfaces_above, current.link) { - view_child_subsurface_create(child, view, subsurface); + // 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, @@ -288,13 +237,10 @@ view_create( view->type = type; view->impl = impl; view->mapped = false; - view->hidden = true; view->decoration = NULL; - view->x = 0; - view->y = 0; - - 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); @@ -302,202 +248,17 @@ view_create( wl_signal_init(&view->events.post_render); wl_signal_init(&view->events.pre_render); + view->desktop_surface.tree = wlr_scene_tree_create( + &view->desktop->strata[KIWMI_STRATUM_NORMAL]->node); + view->desktop_surface.popups_tree = wlr_scene_tree_create( + &view->desktop->strata[KIWMI_STRATUM_POPUPS]->node); + + view_set_hidden(view, true); + wlr_scene_node_lower_to_bottom(&view->desktop_surface.tree->node); + wlr_scene_node_lower_to_bottom(&view->desktop_surface.popups_tree->node); + + wlr_scene_node_set_position(&view->desktop_surface.tree->node, 0, 0); + wlr_scene_node_set_position(&view->desktop_surface.popups_tree->node, 0, 0); + return view; } - -bool -view_child_is_mapped(struct kiwmi_view_child *child) -{ - if (!child->mapped) { - return false; - } - - struct kiwmi_view_child *parent = child->parent; - while (parent) { - if (!parent->mapped) { - return false; - } - parent = parent->parent; - } - - return child->view->mapped; -} - -void -view_child_damage(struct kiwmi_view_child *child) -{ - // Note for later: this is supposed to damage the child and all subchildren - struct kiwmi_output *output; - wl_list_for_each (output, &child->view->desktop->outputs, link) { - output_damage(output); - } -} - -void -view_child_destroy(struct kiwmi_view_child *child) -{ - bool visible = view_child_is_mapped(child) && !child->view->hidden; - if (visible) { - view_child_damage(child); - } - - wl_list_remove(&child->link); - child->parent = NULL; - - struct kiwmi_view_child *subchild, *tmpchild; - wl_list_for_each_safe (subchild, tmpchild, &child->children, link) { - subchild->mapped = false; - view_child_destroy(subchild); - } - - wl_list_remove(&child->commit.link); - wl_list_remove(&child->map.link); - wl_list_remove(&child->unmap.link); - wl_list_remove(&child->new_popup.link); - wl_list_remove(&child->new_subsurface.link); - wl_list_remove(&child->surface_destroy.link); - wl_list_remove(&child->extension_destroy.link); - - free(child); -} - -static void -view_child_subsurface_extension_destroy_notify( - struct wl_listener *listener, - void *UNUSED(data)) -{ - struct kiwmi_view_child *child = - wl_container_of(listener, child, extension_destroy); - view_child_destroy(child); -} - -static void -view_child_surface_destroy_notify( - struct wl_listener *listener, - void *UNUSED(data)) -{ - struct kiwmi_view_child *child = - wl_container_of(listener, child, surface_destroy); - view_child_destroy(child); -} - -static void -view_child_commit_notify(struct wl_listener *listener, void *UNUSED(data)) -{ - struct kiwmi_view_child *child = wl_container_of(listener, child, commit); - if (view_child_is_mapped(child)) { - view_child_damage(child); - } -} - -static void -view_child_new_subsurface_notify(struct wl_listener *listener, void *data) -{ - struct kiwmi_view_child *child = - wl_container_of(listener, child, new_subsurface); - struct wlr_subsurface *subsurface = data; - view_child_subsurface_create(child, child->view, subsurface); -} - -static void -view_child_map_notify(struct wl_listener *listener, void *UNUSED(data)) -{ - struct kiwmi_view_child *child = wl_container_of(listener, child, map); - child->mapped = true; - if (view_child_is_mapped(child)) { - view_child_damage(child); - } -} - -static void -view_child_unmap_notify(struct wl_listener *listener, void *UNUSED(data)) -{ - struct kiwmi_view_child *child = wl_container_of(listener, child, unmap); - if (view_child_is_mapped(child)) { - view_child_damage(child); - } - child->mapped = false; -} - -struct kiwmi_view_child * -view_child_create( - struct kiwmi_view_child *parent, - struct kiwmi_view *view, - struct wlr_surface *wlr_surface, - enum kiwmi_view_child_type type, - const struct kiwmi_view_child_impl *impl) -{ - struct kiwmi_view_child *child = calloc(1, sizeof(*child)); - if (!child) { - wlr_log(WLR_ERROR, "Failed to allocate view_child"); - return NULL; - } - - child->type = type; - child->impl = impl; - child->view = view; - child->wlr_surface = wlr_surface; - child->mapped = false; - - if (parent) { - child->parent = parent; - wl_list_insert(&parent->children, &child->link); - } else { - wl_list_insert(&view->children, &child->link); - } - - wl_list_init(&child->children); - - child->commit.notify = view_child_commit_notify; - wl_signal_add(&wlr_surface->events.commit, &child->commit); - - child->map.notify = view_child_map_notify; - child->unmap.notify = view_child_unmap_notify; - - // wlr_surface doesn't have these events, but its extensions usually do - wl_list_init(&child->map.link); - wl_list_init(&child->unmap.link); - - child->new_subsurface.notify = view_child_new_subsurface_notify; - wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface); - - child->surface_destroy.notify = view_child_surface_destroy_notify; - wl_signal_add(&wlr_surface->events.destroy, &child->surface_destroy); - - // Possibly unused - wl_list_init(&child->new_popup.link); - wl_list_init(&child->extension_destroy.link); - - view_init_subsurfaces(child, child->view); - - return child; -} - -struct kiwmi_view_child * -view_child_subsurface_create( - struct kiwmi_view_child *parent, - struct kiwmi_view *view, - struct wlr_subsurface *subsurface) -{ - struct kiwmi_view_child *child = view_child_create( - parent, view, subsurface->surface, KIWMI_VIEW_CHILD_SUBSURFACE, NULL); - if (!child) { - return NULL; - } - - child->wlr_subsurface = subsurface; - child->mapped = subsurface->mapped; - - if (view_child_is_mapped(child)) { - view_child_damage(child); - } - - wl_signal_add(&subsurface->events.map, &child->map); - wl_signal_add(&subsurface->events.unmap, &child->unmap); - - child->extension_destroy.notify = - view_child_subsurface_extension_destroy_notify; - wl_signal_add(&subsurface->events.destroy, &child->extension_destroy); - - return child; -} diff --git a/kiwmi/desktop/xdg_shell.c b/kiwmi/desktop/xdg_shell.c index 337fd5d..733de40 100644 --- a/kiwmi/desktop/xdg_shell.c +++ b/kiwmi/desktop/xdg_shell.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -18,168 +19,19 @@ #include "desktop/desktop.h" #include "desktop/output.h" +#include "desktop/popup.h" #include "desktop/view.h" #include "input/cursor.h" #include "input/input.h" #include "input/seat.h" #include "server.h" -static struct kiwmi_view_child *view_child_popup_create( - struct kiwmi_view_child *parent, - struct kiwmi_view *view, - struct wlr_xdg_popup *wlr_popup); - -static void -popup_new_popup_notify(struct wl_listener *listener, void *data) -{ - struct kiwmi_view_child *popup = - wl_container_of(listener, popup, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - view_child_popup_create(popup, popup->view, wlr_popup); -} - -static void -popup_extension_destroy_notify(struct wl_listener *listener, void *UNUSED(data)) -{ - struct kiwmi_view_child *popup = - wl_container_of(listener, popup, extension_destroy); - view_child_destroy(popup); -} - -static void -popup_unconstrain(struct kiwmi_view_child *popup) -{ - if (popup->type != KIWMI_VIEW_CHILD_XDG_POPUP) { - wlr_log(WLR_ERROR, "Expected an xdg_popup kiwmi_view_child"); - return; - } - - struct kiwmi_view *view = popup->view; - - // Prefer output at view center - struct wlr_output *output = wlr_output_layout_output_at( - view->desktop->output_layout, - view->x + view->geom.width / 2, - view->y + view->geom.height / 2); - - if (!output) { - // Retry with view top-left corner (if its center is off-screen) - output = wlr_output_layout_output_at( - view->desktop->output_layout, view->x, view->y); - } - - if (!output) { - wlr_log( - WLR_ERROR, "View's output not found, popups may end up invisible"); - return; - } - - double view_ox = view->x; - double view_oy = view->y; - wlr_output_layout_output_coords( - view->desktop->output_layout, output, &view_ox, &view_oy); - - int output_width; - int output_height; - wlr_output_effective_resolution(output, &output_width, &output_height); - - // relative to the view - struct wlr_box output_box = { - .x = -view_ox, - .y = -view_oy, - .width = output_width, - .height = output_height, - }; - - wlr_xdg_popup_unconstrain_from_box(popup->wlr_xdg_popup, &output_box); -} - -static void -popup_reconfigure(struct kiwmi_view_child *popup) -{ - if (popup->type != KIWMI_VIEW_CHILD_XDG_POPUP) { - wlr_log(WLR_ERROR, "Expected an xdg_popup view_child"); - return; - } - - popup_unconstrain(popup); - - struct kiwmi_view_child *subchild; - wl_list_for_each (subchild, &popup->children, link) { - if (subchild->impl && subchild->impl->reconfigure) { - subchild->impl->reconfigure(subchild); - } - } -} - -static const struct kiwmi_view_child_impl xdg_popup_view_child_impl = { - .reconfigure = popup_reconfigure, -}; - -static struct kiwmi_view_child * -view_child_popup_create( - struct kiwmi_view_child *parent, - struct kiwmi_view *view, - struct wlr_xdg_popup *wlr_popup) -{ - struct kiwmi_view_child *child = view_child_create( - parent, - view, - wlr_popup->base->surface, - KIWMI_VIEW_CHILD_XDG_POPUP, - &xdg_popup_view_child_impl); - if (!child) { - return NULL; - } - - child->wlr_xdg_popup = wlr_popup; - child->mapped = wlr_popup->base->mapped; - - if (view_child_is_mapped(child)) { - view_child_damage(child); - } - - wl_signal_add(&wlr_popup->base->events.map, &child->map); - wl_signal_add(&wlr_popup->base->events.unmap, &child->unmap); - - child->new_popup.notify = popup_new_popup_notify; - wl_signal_add(&wlr_popup->base->events.new_popup, &child->new_popup); - - child->extension_destroy.notify = popup_extension_destroy_notify; - wl_signal_add(&wlr_popup->base->events.destroy, &child->extension_destroy); - - popup_unconstrain(child); - - return child; -} - -static void -xdg_surface_new_popup_notify(struct wl_listener *listener, void *data) -{ - struct kiwmi_view *view = wl_container_of(listener, view, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - view_child_popup_create(NULL, view, wlr_popup); -} - -static void -xdg_surface_new_subsurface_notify(struct wl_listener *listener, void *data) -{ - struct kiwmi_view *view = wl_container_of(listener, view, new_subsurface); - struct wlr_subsurface *subsurface = data; - view_child_subsurface_create(NULL, view, subsurface); -} - static void xdg_surface_map_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_view *view = wl_container_of(listener, view, map); view->mapped = true; - struct kiwmi_output *output; - wl_list_for_each (output, &view->desktop->outputs, link) { - output_damage(output); - } - wl_signal_emit(&view->desktop->events.view_map, view); } @@ -188,16 +40,25 @@ 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; - struct kiwmi_output *output; - wl_list_for_each (output, &view->desktop->outputs, link) { - output_damage(output); + 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_server *server = + wl_container_of(view->desktop, server, desktop); + cursor_refresh_focus(server->input.cursor, NULL, NULL, NULL); + + struct kiwmi_seat *seat = server->input.seat; + if (seat->focused_view == view) { + seat->focused_view = NULL; } - - wl_signal_emit(&view->events.unmap, view); } + + wl_signal_emit(&view->events.unmap, view); } static void @@ -205,52 +66,35 @@ xdg_surface_commit_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_view *view = wl_container_of(listener, view, commit); - 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); + struct wlr_box geom; + wlr_xdg_surface_get_geometry(view->xdg_surface, &geom); - if (pixman_region32_not_empty(&view->wlr_surface->buffer_damage)) { - struct kiwmi_output *output; - wl_list_for_each (output, &desktop->outputs, link) { - output_damage(output); - } + if (memcmp(&view->geom, &geom, sizeof(geom)) != 0) { + memcpy(&view->geom, &geom, sizeof(geom)); + + struct kiwmi_desktop *desktop = view->desktop; + struct kiwmi_server *server = wl_container_of(desktop, server, desktop); + cursor_refresh_focus(server->input.cursor, NULL, NULL, NULL); } - - wlr_xdg_surface_get_geometry(view->xdg_surface, &view->geom); } static void xdg_surface_destroy_notify(struct wl_listener *listener, void *UNUSED(data)) { - struct kiwmi_view *view = wl_container_of(listener, view, destroy); - struct kiwmi_desktop *desktop = view->desktop; - struct kiwmi_server *server = wl_container_of(desktop, server, desktop); - struct kiwmi_seat *seat = server->input.seat; + struct kiwmi_view *view = wl_container_of(listener, view, destroy); - if (seat->focused_view == view) { - seat->focused_view = NULL; - } - cursor_refresh_focus(server->input.cursor, NULL, NULL, NULL); - - struct kiwmi_view_child *child, *tmpchild; - wl_list_for_each_safe (child, tmpchild, &view->children, link) { - child->mapped = false; - view_child_destroy(child); - } + wlr_scene_node_destroy(&view->desktop_surface.tree->node); + wlr_scene_node_destroy(&view->desktop_surface.popups_tree->node); if (view->decoration) { view->decoration->view = NULL; } wl_list_remove(&view->link); - wl_list_remove(&view->children); wl_list_remove(&view->map.link); wl_list_remove(&view->unmap.link); wl_list_remove(&view->commit.link); wl_list_remove(&view->destroy.link); - wl_list_remove(&view->new_popup.link); - wl_list_remove(&view->new_subsurface.link); wl_list_remove(&view->request_move.link); wl_list_remove(&view->request_resize.link); @@ -293,15 +137,6 @@ xdg_shell_view_close(struct kiwmi_view *view) } } -static void -xdg_shell_view_for_each_surface( - struct kiwmi_view *view, - wlr_surface_iterator_func_t callback, - void *user_data) -{ - wlr_xdg_surface_for_each_surface(view->xdg_surface, callback, user_data); -} - static pid_t xdg_shell_view_get_pid(struct kiwmi_view *view) { @@ -349,26 +184,13 @@ xdg_shell_view_set_tiled(struct kiwmi_view *view, enum wlr_edges edges) wlr_xdg_toplevel_set_tiled(view->xdg_surface, edges); } -struct wlr_surface * -xdg_shell_view_surface_at( - struct kiwmi_view *view, - double sx, - double sy, - double *sub_x, - double *sub_y) -{ - return wlr_xdg_surface_surface_at(view->xdg_surface, sx, sy, sub_x, sub_y); -} - static const struct kiwmi_view_impl xdg_shell_view_impl = { - .close = xdg_shell_view_close, - .for_each_surface = xdg_shell_view_for_each_surface, - .get_pid = xdg_shell_view_get_pid, - .get_string_prop = xdg_shell_view_get_string_prop, - .set_activated = xdg_shell_view_set_activated, - .set_size = xdg_shell_view_set_size, - .set_tiled = xdg_shell_view_set_tiled, - .surface_at = xdg_shell_view_surface_at, + .close = xdg_shell_view_close, + .get_pid = xdg_shell_view_get_pid, + .get_string_prop = xdg_shell_view_get_string_prop, + .set_activated = xdg_shell_view_set_activated, + .set_size = xdg_shell_view_set_size, + .set_tiled = xdg_shell_view_set_tiled, }; void @@ -380,6 +202,15 @@ xdg_shell_new_surface_notify(struct wl_listener *listener, void *data) if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { wlr_log(WLR_DEBUG, "New xdg_shell popup"); + struct kiwmi_desktop_surface *desktop_surface = + popup_get_desktop_surface(xdg_surface->popup); + if (desktop_surface) { + popup_attach(xdg_surface->popup, desktop_surface); + + struct kiwmi_server *server = + wl_container_of(desktop, server, desktop); + cursor_refresh_focus(server->input.cursor, NULL, NULL, NULL); + } return; } @@ -402,6 +233,9 @@ xdg_shell_new_surface_notify(struct wl_listener *listener, void *data) view->xdg_surface = xdg_surface; view->wlr_surface = xdg_surface->surface; + view->desktop_surface.surface_node = wlr_scene_xdg_surface_create( + &view->desktop_surface.tree->node, xdg_surface); + view->map.notify = xdg_surface_map_notify; wl_signal_add(&xdg_surface->events.map, &view->map); @@ -414,13 +248,6 @@ xdg_shell_new_surface_notify(struct wl_listener *listener, void *data) view->destroy.notify = xdg_surface_destroy_notify; wl_signal_add(&xdg_surface->events.destroy, &view->destroy); - view->new_popup.notify = xdg_surface_new_popup_notify; - wl_signal_add(&xdg_surface->events.new_popup, &view->new_popup); - - view->new_subsurface.notify = xdg_surface_new_subsurface_notify; - wl_signal_add( - &xdg_surface->surface->events.new_subsurface, &view->new_subsurface); - view->request_move.notify = xdg_toplevel_request_move_notify; wl_signal_add( &xdg_surface->toplevel->events.request_move, &view->request_move); @@ -429,7 +256,7 @@ xdg_shell_new_surface_notify(struct wl_listener *listener, void *data) wl_signal_add( &xdg_surface->toplevel->events.request_resize, &view->request_resize); - view_init_subsurfaces(NULL, view); + wlr_xdg_surface_get_geometry(view->xdg_surface, &view->geom); wl_list_insert(&desktop->views, &view->link); } 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/input/seat.c b/kiwmi/input/seat.c index a1ac68b..c10a44f 100644 --- a/kiwmi/input/seat.c +++ b/kiwmi/input/seat.c @@ -83,6 +83,10 @@ seat_focus_view(struct kiwmi_seat *seat, struct kiwmi_view *view) // move view to front wl_list_remove(&view->link); wl_list_insert(&desktop->views, &view->link); + + wlr_scene_node_raise_to_top(&view->desktop_surface.tree->node); + wlr_scene_node_raise_to_top(&view->desktop_surface.popups_tree->node); + cursor_refresh_focus(seat->input->cursor, NULL, NULL, NULL); seat->focused_view = view; @@ -112,14 +116,6 @@ request_set_cursor_notify(struct wl_listener *listener, void *data) return; } - struct kiwmi_input *input = seat->input; - struct kiwmi_server *server = wl_container_of(input, server, input); - - struct kiwmi_output *output; - wl_list_for_each (output, &server->desktop.outputs, link) { - output_damage(output); - } - wlr_cursor_set_surface( cursor->cursor, event->surface, event->hotspot_x, event->hotspot_y); } 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_output.c b/kiwmi/luak/kiwmi_output.c index e76c61c..42740ab 100644 --- a/kiwmi/luak/kiwmi_output.c +++ b/kiwmi/luak/kiwmi_output.c @@ -98,23 +98,6 @@ l_kiwmi_output_pos(lua_State *L) return 2; } -static int -l_kiwmi_output_redraw(lua_State *L) -{ - struct kiwmi_object *obj = - *(struct kiwmi_object **)luaL_checkudata(L, 1, "kiwmi_output"); - - if (!obj->valid) { - return luaL_error(L, "kiwmi_output no longer valid"); - } - - struct kiwmi_output *output = obj->object; - - output_damage(output); - - return 0; -} - static int l_kiwmi_output_size(lua_State *L) { @@ -168,7 +151,6 @@ static const luaL_Reg kiwmi_output_methods[] = { {"name", l_kiwmi_output_name}, {"on", luaK_callback_register_dispatch}, {"pos", l_kiwmi_output_pos}, - {"redraw", l_kiwmi_output_redraw}, {"size", l_kiwmi_output_size}, {"usable_area", l_kiwmi_output_usable_area}, {NULL, NULL}, diff --git a/kiwmi/luak/kiwmi_renderer.c b/kiwmi/luak/kiwmi_renderer.c deleted file mode 100644 index 46fcf27..0000000 --- a/kiwmi/luak/kiwmi_renderer.c +++ /dev/null @@ -1,100 +0,0 @@ -/* 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 "luak/kiwmi_renderer.h" - -#include -#include - -#include -#include -#include -#include - -#include "color.h" -#include "desktop/output.h" -#include "luak/lua_compat.h" -#include "luak/luak.h" - -struct kiwmi_renderer { - struct wlr_renderer *wlr_renderer; - struct kiwmi_output *output; -}; - -static int -l_kiwmi_renderer_draw_rect(lua_State *L) -{ - struct kiwmi_renderer *renderer = - (struct kiwmi_renderer *)luaL_checkudata(L, 1, "kiwmi_renderer"); - luaL_checktype(L, 2, LUA_TSTRING); // color - luaL_checktype(L, 3, LUA_TNUMBER); // x - luaL_checktype(L, 4, LUA_TNUMBER); // y - luaL_checktype(L, 5, LUA_TNUMBER); // width - luaL_checktype(L, 6, LUA_TNUMBER); // height - - struct wlr_renderer *wlr_renderer = renderer->wlr_renderer; - struct kiwmi_output *output = renderer->output; - struct wlr_output *wlr_output = output->wlr_output; - - float color[4]; - if (!color_parse(lua_tostring(L, 2), color)) { - return luaL_argerror(L, 2, "not a valid color"); - } - - struct wlr_box box = { - .x = lua_tonumber(L, 3), - .y = lua_tonumber(L, 4), - .width = lua_tonumber(L, 5), - .height = lua_tonumber(L, 6), - }; - - wlr_render_rect(wlr_renderer, &box, color, wlr_output->transform_matrix); - - return 0; -} - -static const luaL_Reg kiwmi_renderer_methods[] = { - {"draw_rect", l_kiwmi_renderer_draw_rect}, - {NULL, NULL}, -}; - -int -luaK_kiwmi_renderer_new(lua_State *L) -{ - luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); // kiwmi_lua - luaL_checktype(L, 2, LUA_TLIGHTUSERDATA); // wlr_renderer - luaL_checktype(L, 3, LUA_TLIGHTUSERDATA); // wlr_output - - struct kiwmi_lua *UNUSED(lua) = lua_touserdata(L, 1); - struct wlr_renderer *wlr_renderer = lua_touserdata(L, 2); - struct kiwmi_output *output = lua_touserdata(L, 3); - - struct kiwmi_renderer *renderer_ud = - lua_newuserdata(L, sizeof(*renderer_ud)); - luaL_getmetatable(L, "kiwmi_renderer"); - lua_setmetatable(L, -2); - - renderer_ud->wlr_renderer = wlr_renderer; - renderer_ud->output = output; - - return 1; -} - -int -luaK_kiwmi_renderer_register(lua_State *L) -{ - luaL_newmetatable(L, "kiwmi_renderer"); - - lua_pushvalue(L, -1); - lua_setfield(L, -2, "__index"); - luaC_setfuncs(L, kiwmi_renderer_methods, 0); - - lua_pushcfunction(L, luaK_usertype_ref_equal); - lua_setfield(L, -2, "__eq"); - - return 0; -} diff --git a/kiwmi/luak/kiwmi_server.c b/kiwmi/luak/kiwmi_server.c index 4e41d94..cf44ea2 100644 --- a/kiwmi/luak/kiwmi_server.c +++ b/kiwmi/luak/kiwmi_server.c @@ -65,10 +65,12 @@ l_kiwmi_server_bg_color(lua_State *L) return luaL_argerror(L, 2, "not a valid color"); } - server->desktop.bg_color[0] = color[0]; - server->desktop.bg_color[1] = color[1]; - server->desktop.bg_color[2] = color[2]; - // ignore alpha + // Ignore alpha (color channels are already premultiplied) + color[3] = 1.0f; + + wlr_scene_rect_set_color(server->desktop.background_rect, color); + bool black = color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f; + wlr_scene_node_set_enabled(&server->desktop.background_rect->node, !black); return 0; } @@ -308,12 +310,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 791347b..84f9f4c 100644 --- a/kiwmi/luak/kiwmi_view.c +++ b/kiwmi/luak/kiwmi_view.c @@ -15,13 +15,13 @@ #include #include +#include "desktop/desktop_surface.h" #include "desktop/output.h" #include "desktop/view.h" #include "desktop/xdg_shell.h" #include "input/seat.h" #include "luak/kiwmi_lua_callback.h" #include "luak/kiwmi_output.h" -#include "luak/kiwmi_renderer.h" #include "luak/lua_compat.h" #include "server.h" @@ -121,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; } @@ -138,7 +142,7 @@ l_kiwmi_view_hide(lua_State *L) struct kiwmi_view *view = obj->object; - view->hidden = true; + view_set_hidden(view, true); return 0; } @@ -276,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; } @@ -316,7 +323,7 @@ l_kiwmi_view_show(lua_State *L) struct kiwmi_view *view = obj->object; - view->hidden = false; + view_set_hidden(view, false); return 0; } @@ -471,65 +478,6 @@ kiwmi_view_on_destroy_notify(struct wl_listener *listener, void *data) } } -static void -kiwmi_view_on_render_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_render_data *rdata = data; - - struct kiwmi_view *view = rdata->data; - struct wlr_renderer *renderer = rdata->renderer; - struct kiwmi_output *output = rdata->output->data; - - lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); - - lua_newtable(L); - - lua_pushcfunction(L, luaK_kiwmi_view_new); - lua_pushlightuserdata(L, server->lua); - lua_pushlightuserdata(L, view); - - if (lua_pcall(L, 2, 1, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - lua_pop(L, 1); - return; - } - - lua_setfield(L, -2, "view"); - - lua_pushcfunction(L, luaK_kiwmi_output_new); - lua_pushlightuserdata(L, server->lua); - lua_pushlightuserdata(L, output); - - if (lua_pcall(L, 2, 1, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - lua_pop(L, 1); - return; - } - - lua_setfield(L, -2, "output"); - - lua_pushcfunction(L, luaK_kiwmi_renderer_new); - lua_pushlightuserdata(L, server->lua); - lua_pushlightuserdata(L, renderer); - lua_pushlightuserdata(L, output); - - if (lua_pcall(L, 3, 1, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - lua_pop(L, 1); - return; - } - - lua_setfield(L, -2, "renderer"); - - if (lua_pcall(L, 1, 0, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - lua_pop(L, 1); - } -} - static void kiwmi_view_on_request_move_notify(struct wl_listener *listener, void *data) { @@ -644,62 +592,16 @@ l_kiwmi_view_on_destroy(lua_State *L) } static int -l_kiwmi_view_on_post_render(lua_State *L) +l_kiwmi_view_on_post_render(lua_State *UNUSED(L)) { - struct kiwmi_object *obj = - *(struct kiwmi_object **)luaL_checkudata(L, 1, "kiwmi_view"); - luaL_checktype(L, 2, LUA_TFUNCTION); - - if (!obj->valid) { - return luaL_error(L, "kiwmi_view no longer valid"); - } - - struct kiwmi_view *view = obj->object; - struct kiwmi_desktop *desktop = view->desktop; - struct kiwmi_server *server = wl_container_of(desktop, server, desktop); - - lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); - lua_pushlightuserdata(L, server); - lua_pushvalue(L, 2); - lua_pushlightuserdata(L, kiwmi_view_on_render_notify); - lua_pushlightuserdata(L, &view->events.post_render); - lua_pushlightuserdata(L, obj); - - if (lua_pcall(L, 5, 0, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - return 0; - } - + // noop return 0; } static int -l_kiwmi_view_on_pre_render(lua_State *L) +l_kiwmi_view_on_pre_render(lua_State *UNUSED(L)) { - struct kiwmi_object *obj = - *(struct kiwmi_object **)luaL_checkudata(L, 1, "kiwmi_view"); - luaL_checktype(L, 2, LUA_TFUNCTION); - - if (!obj->valid) { - return luaL_error(L, "kiwmi_view no longer valid"); - } - - struct kiwmi_view *view = obj->object; - struct kiwmi_desktop *desktop = view->desktop; - struct kiwmi_server *server = wl_container_of(desktop, server, desktop); - - lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); - lua_pushlightuserdata(L, server); - lua_pushvalue(L, 2); - lua_pushlightuserdata(L, kiwmi_view_on_render_notify); - lua_pushlightuserdata(L, &view->events.pre_render); - lua_pushlightuserdata(L, obj); - - if (lua_pcall(L, 5, 0, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - return 0; - } - + // noop return 0; } diff --git a/kiwmi/luak/luak.c b/kiwmi/luak/luak.c index f00a407..0a34b94 100644 --- a/kiwmi/luak/luak.c +++ b/kiwmi/luak/luak.c @@ -18,7 +18,6 @@ #include "luak/kiwmi_keyboard.h" #include "luak/kiwmi_lua_callback.h" #include "luak/kiwmi_output.h" -#include "luak/kiwmi_renderer.h" #include "luak/kiwmi_server.h" #include "luak/kiwmi_view.h" @@ -220,8 +219,6 @@ luaK_create(struct kiwmi_server *server) error |= lua_pcall(L, 0, 0, 0); lua_pushcfunction(L, luaK_kiwmi_output_register); error |= lua_pcall(L, 0, 0, 0); - lua_pushcfunction(L, luaK_kiwmi_renderer_register); - error |= lua_pcall(L, 0, 0, 0); lua_pushcfunction(L, luaK_kiwmi_server_register); error |= lua_pcall(L, 0, 0, 0); lua_pushcfunction(L, luaK_kiwmi_view_register); diff --git a/kiwmi/meson.build b/kiwmi/meson.build index 13f7c9b..d05e559 100644 --- a/kiwmi/meson.build +++ b/kiwmi/meson.build @@ -3,8 +3,11 @@ kiwmi_sources = files( 'server.c', 'color.c', 'desktop/desktop.c', + 'desktop/desktop_surface.c', 'desktop/layer_shell.c', 'desktop/output.c', + 'desktop/popup.c', + 'desktop/stratum.c', 'desktop/view.c', 'desktop/xdg_shell.c', 'input/cursor.c', @@ -17,7 +20,6 @@ kiwmi_sources = files( 'luak/kiwmi_keyboard.c', 'luak/kiwmi_lua_callback.c', 'luak/kiwmi_output.c', - 'luak/kiwmi_renderer.c', 'luak/kiwmi_server.c', 'luak/kiwmi_view.c', 'luak/lua_compat.c', diff --git a/kiwmi/server.c b/kiwmi/server.c index ba0e74c..2b55371 100644 --- a/kiwmi/server.c +++ b/kiwmi/server.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "luak/luak.h" @@ -67,6 +68,7 @@ server_init(struct kiwmi_server *server, char *config_path) wlr_data_control_manager_v1_create(server->wl_display); wlr_gamma_control_manager_v1_create(server->wl_display); wlr_primary_selection_v1_device_manager_create(server->wl_display); + wlr_viewporter_create(server->wl_display); server->socket = wl_display_add_socket_auto(server->wl_display); if (!server->socket) { diff --git a/lua_docs.md b/lua_docs.md index 3eb0b26..7f63b60 100644 --- a/lua_docs.md +++ b/lua_docs.md @@ -240,10 +240,6 @@ Used to register event listeners. Get the position of the output. Returns two parameters: `x` and `y`. -#### output:redraw() - -Force the output to redraw. Useful e.g. when you know the view `pre_render`/`post_render` callbacks are going to change. - #### output:size() Get the size of the output. @@ -270,17 +266,6 @@ Callback receives a table containing the `output`, the new `width`, and the new The usable area of this output has changed, e.g. because the output was resized or the bars around it changed. Callback receives a table containing the `output` and the new `x`, `y`, `width` and `height`. -## kiwmi_renderer - -Represents a rendering context, to draw on the output. - -### Methods - -#### renderer:draw_rect(color, x, y, w, h) - -Draws a rect at the given position. -Color is a string in the form #rrggbb or #rrggbbaa. - ## kiwmi_view Represents a view (a window in kiwmi terms). @@ -373,17 +358,11 @@ Callback receives the view. #### post_render -The view finished being rendered. -Callback receives a table with the `view`, the `renderer` and the `output`. - -This event occurs once per output the view might be drawn on. +This is a no-op event. Temporarily preserved only to make config migration easier. #### pre_render -The view is about to be rendered. -Callback receives a table with the `view`, the `renderer` and the `output`. - -This event occurs once per output the view might be drawn on. +This is a no-op event. Temporarily preserved only to make config migration easier. #### request_move