Support xdg-shell and add basic rendering

This commit is contained in:
buffet 2019-12-21 14:06:56 +00:00
parent 3673ae37ca
commit cce0d0ba15
9 changed files with 279 additions and 6 deletions

View file

@ -13,10 +13,13 @@
struct kiwmi_desktop {
struct wlr_compositor *compositor;
struct wlr_xdg_shell *xdg_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
struct wl_listener xdg_shell_new_surface;
struct wl_listener new_output;
};

55
include/desktop/view.h Normal file
View file

@ -0,0 +1,55 @@
/* 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_VIEW_H
#define KIWMI_DESKTOP_VIEW_H
#include <stdbool.h>
#include <stdlib.h>
#include <wayland-server.h>
#include <wlr/types/wlr_xdg_shell.h>
enum kiwmi_view_type {
KIWMI_VIEW_XDG_SHELL,
};
struct kiwmi_view {
struct wl_list link;
struct kiwmi_desktop *desktop;
const struct kiwmi_view_impl *impl;
enum kiwmi_view_type type;
union {
struct wlr_xdg_surface *xdg_surface;
};
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
double x;
double y;
bool mapped;
};
struct kiwmi_view_impl {
void (*for_each_surface)(
struct kiwmi_view *view,
wlr_surface_iterator_func_t iterator,
void *user_data);
};
void kiwmi_view_for_each_surface(
struct kiwmi_view *view,
wlr_surface_iterator_func_t iterator,
void *user_data);
#endif /* KIWMI_DESKTOP_VIEW_H */

View file

@ -0,0 +1,15 @@
/* 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_XDG_SHELL_H
#define KIWMI_DESKTOP_XDG_SHELL_H
#include <wayland-server.h>
void xdg_shell_new_surface_notify(struct wl_listener *listener, void *data);
#endif /* KIWMI_DESKTOP_XDG_SHELL_H */

View file

@ -13,10 +13,13 @@
#include <wlr/backend.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
#include "desktop/output.h"
#include "desktop/xdg_shell.h"
#include "server.h"
bool
@ -28,9 +31,18 @@ desktop_init(struct kiwmi_desktop *desktop, struct wlr_renderer *renderer)
wlr_data_device_manager_create(server->wl_display);
desktop->output_layout = wlr_output_layout_create();
wlr_xdg_output_manager_v1_create(server->wl_display, desktop->output_layout);
wlr_export_dmabuf_manager_v1_create(server->wl_display);
wlr_xdg_output_manager_v1_create(
server->wl_display, desktop->output_layout);
desktop->xdg_shell = wlr_xdg_shell_create(server->wl_display);
desktop->xdg_shell_new_surface.notify = xdg_shell_new_surface_notify;
wl_signal_add(
&desktop->xdg_shell->events.new_surface,
&desktop->xdg_shell_new_surface);
wl_list_init(&desktop->outputs);
wl_list_init(&desktop->views);
desktop->new_output.notify = new_output_notify;
wl_signal_add(&server->backend->events.new_output, &desktop->new_output);

View file

@ -12,25 +12,78 @@
#include <wayland-server.h>
#include <wlr/backend.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/util/log.h>
#include "desktop/desktop.h"
#include "desktop/view.h"
#include "input/cursor.h"
#include "input/input.h"
#include "server.h"
struct render_data {
struct wlr_output *output;
struct kiwmi_view *view;
struct wlr_renderer *renderer;
struct timespec *when;
};
static void
render_surface(struct wlr_surface *surface, int sx, int sy, void *data)
{
struct render_data *rdata = data;
struct kiwmi_view *view = rdata->view;
struct wlr_output *output = rdata->output;
struct wlr_texture *texture = wlr_surface_get_texture(surface);
if (!texture) {
return;
}
double ox = 0;
double oy = 0;
wlr_output_layout_output_coords(
view->desktop->output_layout, output, &ox, &oy);
ox += view->x + sx;
oy += view->y + sy;
struct wlr_box box = {
.x = ox * output->scale,
.y = oy * output->scale,
.width = surface->current.width * output->scale,
.height = surface->current.height * 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, output->transform_matrix);
wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1);
wlr_surface_send_frame_done(surface, rdata->when);
}
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_renderer *renderer =
wlr_backend_get_renderer(wlr_output->backend);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if (!wlr_output_attach_render(wlr_output, NULL)) {
wlr_log(WLR_ERROR, "Failed to attach renderer to output");
return;
}
@ -39,12 +92,28 @@ output_frame_notify(struct wl_listener *listener, void *data)
wlr_output_effective_resolution(wlr_output, &width, &height);
{
wlr_renderer_begin(renderer, width, height);
wlr_renderer_clear(renderer, (float[]){0.0f, 1.0f, 0.0f, 1.0f});
struct kiwmi_view *view;
wl_list_for_each_reverse(view, &desktop->views, link)
{
if (!view->mapped) {
continue;
}
struct render_data rdata = {
.output = output->wlr_output,
.view = view,
.renderer = renderer,
.when = &now,
};
kiwmi_view_for_each_surface(view, render_surface, &rdata);
}
wlr_output_render_software_cursors(wlr_output, NULL);
wlr_renderer_end(renderer);
}
wlr_output_commit(wlr_output);
}

19
kiwmi/desktop/view.c Normal file
View file

@ -0,0 +1,19 @@
/* 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/view.h"
void
kiwmi_view_for_each_surface(
struct kiwmi_view *view,
wlr_surface_iterator_func_t iterator,
void *user_data)
{
if (view->impl->for_each_surface) {
view->impl->for_each_surface(view, iterator, user_data);
}
}

98
kiwmi/desktop/xdg_shell.c Normal file
View file

@ -0,0 +1,98 @@
/* 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/xdg_shell.h"
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#include "desktop/desktop.h"
#include "desktop/view.h"
#include "server.h"
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;
}
static void
xdg_surface_unmap_notify(struct wl_listener *listener, void *UNUSED(data))
{
struct kiwmi_view *view = wl_container_of(listener, view, map);
view->mapped = false;
}
static void
xdg_surface_destroy_notify(struct wl_listener *listener, void *UNUSED(data))
{
struct kiwmi_view *view = wl_container_of(listener, view, destroy);
wl_list_remove(&view->map.link);
wl_list_remove(&view->unmap.link);
wl_list_remove(&view->destroy.link);
free(view);
}
static void
xdg_shell_view_for_each_surface(
struct kiwmi_view *view,
wlr_surface_iterator_func_t iterator,
void *user_data)
{
wlr_xdg_surface_for_each_surface(view->xdg_surface, iterator, user_data);
}
static const struct kiwmi_view_impl xdg_shell_view_impl = {
.for_each_surface = xdg_shell_view_for_each_surface,
};
void
xdg_shell_new_surface_notify(struct wl_listener *listener, void *data)
{
struct wlr_xdg_surface *xdg_surface = data;
struct kiwmi_desktop *desktop =
wl_container_of(listener, desktop, xdg_shell_new_surface);
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
wlr_log(WLR_DEBUG, "New xdg_shell popup");
return;
}
wlr_log(
WLR_DEBUG,
"New xdg_shell toplevel title='%s' app_id='%s'",
xdg_surface->toplevel->title,
xdg_surface->toplevel->app_id);
wlr_xdg_surface_ping(xdg_surface);
struct kiwmi_view *view = malloc(sizeof(*view));
if (!view) {
wlr_log(WLR_ERROR, "Failed to allocate view");
return;
}
view->desktop = desktop;
view->type = KIWMI_VIEW_XDG_SHELL;
view->impl = &xdg_shell_view_impl;
view->xdg_surface = xdg_surface;
view->mapped = false;
view->map.notify = xdg_surface_map_notify;
wl_signal_add(&xdg_surface->events.map, &view->map);
view->unmap.notify = xdg_surface_unmap_notify;
wl_signal_add(&xdg_surface->events.unmap, &view->unmap);
view->destroy.notify = xdg_surface_destroy_notify;
wl_signal_add(&xdg_surface->events.destroy, &view->destroy);
wl_list_insert(&desktop->views, &view->link);
}

View file

@ -4,6 +4,8 @@ kiwmi_sources = files(
'server.c',
'desktop/desktop.c',
'desktop/output.c',
'desktop/view.c',
'desktop/xdg_shell.c',
'input/cursor.c',
'input/input.c',
'input/keyboard.c',