Support xdg-shell and add basic rendering
This commit is contained in:
parent
3673ae37ca
commit
cce0d0ba15
9 changed files with 279 additions and 6 deletions
|
@ -13,10 +13,13 @@
|
||||||
|
|
||||||
struct kiwmi_desktop {
|
struct kiwmi_desktop {
|
||||||
struct wlr_compositor *compositor;
|
struct wlr_compositor *compositor;
|
||||||
|
struct wlr_xdg_shell *xdg_shell;
|
||||||
struct wlr_data_device_manager *data_device_manager;
|
struct wlr_data_device_manager *data_device_manager;
|
||||||
struct wlr_output_layout *output_layout;
|
struct wlr_output_layout *output_layout;
|
||||||
struct wl_list outputs; // struct kiwmi_output::link
|
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;
|
struct wl_listener new_output;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
55
include/desktop/view.h
Normal file
55
include/desktop/view.h
Normal 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 */
|
15
include/desktop/xdg_shell.h
Normal file
15
include/desktop/xdg_shell.h
Normal 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 */
|
|
@ -13,10 +13,13 @@
|
||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/types/wlr_compositor.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include <wlr/types/wlr_data_device.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_output_layout.h>
|
||||||
#include <wlr/types/wlr_xdg_output_v1.h>
|
#include <wlr/types/wlr_xdg_output_v1.h>
|
||||||
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
|
|
||||||
#include "desktop/output.h"
|
#include "desktop/output.h"
|
||||||
|
#include "desktop/xdg_shell.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -28,9 +31,18 @@ desktop_init(struct kiwmi_desktop *desktop, struct wlr_renderer *renderer)
|
||||||
wlr_data_device_manager_create(server->wl_display);
|
wlr_data_device_manager_create(server->wl_display);
|
||||||
desktop->output_layout = wlr_output_layout_create();
|
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->outputs);
|
||||||
|
wl_list_init(&desktop->views);
|
||||||
|
|
||||||
desktop->new_output.notify = new_output_notify;
|
desktop->new_output.notify = new_output_notify;
|
||||||
wl_signal_add(&server->backend->events.new_output, &desktop->new_output);
|
wl_signal_add(&server->backend->events.new_output, &desktop->new_output);
|
||||||
|
|
|
@ -12,25 +12,78 @@
|
||||||
#include <wayland-server.h>
|
#include <wayland-server.h>
|
||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
|
#include <wlr/types/wlr_matrix.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
|
#include <wlr/types/wlr_surface.h>
|
||||||
#include <wlr/types/wlr_xcursor_manager.h>
|
#include <wlr/types/wlr_xcursor_manager.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
#include "desktop/desktop.h"
|
#include "desktop/desktop.h"
|
||||||
|
#include "desktop/view.h"
|
||||||
#include "input/cursor.h"
|
#include "input/cursor.h"
|
||||||
#include "input/input.h"
|
#include "input/input.h"
|
||||||
#include "server.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
|
static void
|
||||||
output_frame_notify(struct wl_listener *listener, void *data)
|
output_frame_notify(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
struct kiwmi_output *output = wl_container_of(listener, output, frame);
|
struct kiwmi_output *output = wl_container_of(listener, output, frame);
|
||||||
struct wlr_output *wlr_output = data;
|
struct wlr_output *wlr_output = data;
|
||||||
|
struct kiwmi_desktop *desktop = output->desktop;
|
||||||
struct wlr_renderer *renderer =
|
struct wlr_renderer *renderer =
|
||||||
wlr_backend_get_renderer(wlr_output->backend);
|
wlr_backend_get_renderer(wlr_output->backend);
|
||||||
|
|
||||||
|
struct timespec now;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
if (!wlr_output_attach_render(wlr_output, NULL)) {
|
if (!wlr_output_attach_render(wlr_output, NULL)) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to attach renderer to output");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,12 +92,28 @@ output_frame_notify(struct wl_listener *listener, void *data)
|
||||||
|
|
||||||
wlr_output_effective_resolution(wlr_output, &width, &height);
|
wlr_output_effective_resolution(wlr_output, &width, &height);
|
||||||
|
|
||||||
{
|
|
||||||
wlr_renderer_begin(renderer, width, height);
|
wlr_renderer_begin(renderer, width, height);
|
||||||
wlr_renderer_clear(renderer, (float[]){0.0f, 1.0f, 0.0f, 1.0f});
|
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_output_render_software_cursors(wlr_output, NULL);
|
||||||
wlr_renderer_end(renderer);
|
wlr_renderer_end(renderer);
|
||||||
}
|
|
||||||
|
|
||||||
wlr_output_commit(wlr_output);
|
wlr_output_commit(wlr_output);
|
||||||
}
|
}
|
||||||
|
|
19
kiwmi/desktop/view.c
Normal file
19
kiwmi/desktop/view.c
Normal 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
98
kiwmi/desktop/xdg_shell.c
Normal 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);
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ kiwmi_sources = files(
|
||||||
'server.c',
|
'server.c',
|
||||||
'desktop/desktop.c',
|
'desktop/desktop.c',
|
||||||
'desktop/output.c',
|
'desktop/output.c',
|
||||||
|
'desktop/view.c',
|
||||||
|
'desktop/xdg_shell.c',
|
||||||
'input/cursor.c',
|
'input/cursor.c',
|
||||||
'input/input.c',
|
'input/input.c',
|
||||||
'input/keyboard.c',
|
'input/keyboard.c',
|
||||||
|
|
Loading…
Reference in a new issue