Merge pull request #50 from tiosgz/wlr-scene
This commit is contained in:
commit
7faf4a3f8b
27 changed files with 707 additions and 1277 deletions
|
@ -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;
|
||||
|
|
45
include/desktop/desktop_surface.h
Normal file
45
include/desktop/desktop_surface.h
Normal 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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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
20
include/desktop/popup.h
Normal 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
33
include/desktop/stratum.h
Normal 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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
87
kiwmi/desktop/desktop_surface.c
Normal file
87
kiwmi/desktop/desktop_surface.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
119
kiwmi/desktop/popup.c
Normal 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
33
kiwmi/desktop/stratum.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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) {
|
||||
|
|
25
lua_docs.md
25
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
|
||||
|
||||
|
|
Loading…
Reference in a new issue