Merge pull request #50 from tiosgz/wlr-scene

This commit is contained in:
buffet 2022-07-30 20:49:54 +00:00 committed by GitHub
commit 7faf4a3f8b
27 changed files with 707 additions and 1277 deletions

View file

@ -9,23 +9,32 @@
#define KIWMI_DESKTOP_DESKTOP_H
#include <wayland-server.h>
#include <wlr/types/wlr_scene.h>
#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;

View file

@ -0,0 +1,45 @@
/* 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/.
*/
#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 */

View file

@ -14,12 +14,15 @@
#include <wlr/types/wlr_surface.h>
#include <wlr/util/box.h>
#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 */

View file

@ -11,19 +11,22 @@
#include <wayland-server.h>
#include <wlr/util/box.h>
#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 */

20
include/desktop/popup.h Normal file
View file

@ -0,0 +1,20 @@
/* 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/.
*/
#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 */

33
include/desktop/stratum.h Normal file
View file

@ -0,0 +1,33 @@
/* 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/.
*/
#ifndef KIWMI_DESKTOP_STRATUM_H
#define KIWMI_DESKTOP_STRATUM_H
#include <stdint.h>
/**
* 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 */

View file

@ -17,6 +17,8 @@
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/edges.h>
#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 */

View file

@ -1,16 +0,0 @@
/* 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/.
*/
#ifndef KIWMI_LUAK_KIWMI_RENDERER_H
#define KIWMI_LUAK_KIWMI_RENDERER_H
#include <lua.h>
int luaK_kiwmi_renderer_new(lua_State *L);
int luaK_kiwmi_renderer_register(lua_State *L);
#endif /* KIWMI_LUAK_KIWMI_RENDERER_H */

View file

@ -17,16 +17,21 @@
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#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

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

@ -15,7 +15,9 @@
#include <wlr/util/log.h>
#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);
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);

View file

@ -18,6 +18,7 @@
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/util/log.h>
@ -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);
}
}
}
}

119
kiwmi/desktop/popup.c Normal file
View file

@ -0,0 +1,119 @@
/* 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/popup.h"
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#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;
}

33
kiwmi/desktop/stratum.c Normal file
View file

@ -0,0 +1,33 @@
/* 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 <stdint.h>
#include <wlr/util/log.h>
#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;
}
}

View file

@ -8,9 +8,11 @@
#include "desktop/view.h"
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/util/log.h>
#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;
}
if (surface_at(view, surface, lx, ly, sx, sy)) {
return view;
}
}
struct kiwmi_desktop_surface *desktop_surface =
desktop_surface_at(desktop, lx, ly);
if (!desktop_surface
|| desktop_surface->type != KIWMI_DESKTOP_SURFACE_VIEW) {
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;
}

View file

@ -11,6 +11,7 @@
#include <pixman.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/edges.h>
@ -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;
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);
}
}
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 wlr_box geom;
wlr_xdg_surface_get_geometry(view->xdg_surface, &geom);
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);
struct kiwmi_cursor *cursor = server->input.cursor;
cursor_refresh_focus(cursor, NULL, NULL, NULL);
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);
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;
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,
};
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);
}

View file

@ -14,6 +14,7 @@
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/util/log.h>
@ -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 (surface != seat->pointer_state.focused_surface) {
wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
}
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) {
} 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);
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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},

View file

@ -1,100 +0,0 @@
/* 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 "luak/kiwmi_renderer.h"
#include <stdlib.h>
#include <string.h>
#include <lauxlib.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_output.h>
#include <wlr/util/log.h>
#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;
}

View file

@ -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);

View file

@ -15,13 +15,13 @@
#include <wlr/util/edges.h>
#include <wlr/util/log.h>
#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;
}

View file

@ -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);

View file

@ -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',

View file

@ -20,6 +20,7 @@
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/util/log.h>
#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) {

View file

@ -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