#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <wl.h>
#include "xdg-decoration-unstable-v1-client-protocol.h"
#include <wlr/interfaces/wlr_buffer.h>
#ifdef ARK_HAVE_CAIRO
#include <cairo.h>
#include <drm_fourcc.h>
#endif
// This macro is responsible for calling a handler on a world. This macro will
// acquire the world's lock, call the member with the arguments and update the
// state.
//
// This only works on function which have the format:
//
// opqst_t function(args ..., opqst_t state);
//
// Note that the state parameter is omitted from this macro.
#define world_call_update_state(world, member, ...) \
do { \
world_t *sl__ = &(world); \
pthread_mutex_lock(&sl__->lock); \
sl__->state = sl__->member(__VA_ARGS__, sl__->state); \
pthread_mutex_unlock(&sl__->lock); \
world_run_requested_actions(sl__); \
} while (0)
#ifdef ARK_HAVE_CAIRO
struct montis_image_buffer {
struct wlr_buffer base;
cairo_surface_t *surface;
uint32_t drm_format;
};
static void image_buffer_destroy(struct wlr_buffer *wlr_buffer)
{
struct montis_image_buffer *buffer =
wl_container_of(wlr_buffer, buffer, base);
cairo_surface_destroy(buffer->surface);
free(buffer);
}
static bool image_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer,
uint32_t flags, void **data,
uint32_t *format, size_t *stride)
{
if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) {
return false;
}
struct montis_image_buffer *buffer =
wl_container_of(wlr_buffer, buffer, base);
cairo_surface_flush(buffer->surface);
*data = cairo_image_surface_get_data(buffer->surface);
*stride = cairo_image_surface_get_stride(buffer->surface);
*format = buffer->drm_format;
return true;
}
static void image_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {}
static const struct wlr_buffer_impl image_buffer_impl = {
.destroy = image_buffer_destroy,
.begin_data_ptr_access = image_buffer_begin_data_ptr_access,
.end_data_ptr_access = image_buffer_end_data_ptr_access,
};
static struct wlr_buffer *load_background_buffer(const char *path)
{
cairo_surface_t *surface = cairo_image_surface_create_from_png(path);
if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy(surface);
wlr_log(WLR_ERROR, "failed to load background image: %s", path);
return NULL;
}
cairo_format_t format = cairo_image_surface_get_format(surface);
uint32_t drm_format = DRM_FORMAT_ARGB8888;
if (format == CAIRO_FORMAT_RGB24) {
drm_format = DRM_FORMAT_XRGB8888;
}
else if (format != CAIRO_FORMAT_ARGB32) {
cairo_surface_destroy(surface);
wlr_log(WLR_ERROR, "unsupported background image format: %d", format);
return NULL;
}
int width = cairo_image_surface_get_width(surface);
int height = cairo_image_surface_get_height(surface);
struct montis_image_buffer *buffer = calloc(1, sizeof(*buffer));
if (!buffer) {
cairo_surface_destroy(surface);
return NULL;
}
wlr_buffer_init(&buffer->base, &image_buffer_impl, width, height);
buffer->surface = surface;
buffer->drm_format = drm_format;
return &buffer->base;
}
#else
static struct wlr_buffer *load_background_buffer(const char *path)
{
(void)path;
wlr_log(WLR_ERROR, "backgrounds require cairo support");
return NULL;
}
#endif
static bool background_accepts_input(struct wlr_scene_buffer *buffer,
double *sx, double *sy)
{
(void)buffer;
(void)sx;
(void)sy;
return false;
}
static void output_update_background(struct montis_output *output)
{
struct montis_server *server = output->server;
if (!server->background_buffer) {
return;
}
if (!output->background) {
output->background = wlr_scene_buffer_create(&server->scene->tree,
server->background_buffer);
if (!output->background) {
wlr_log(WLR_ERROR, "failed to create background node");
return;
}
output->background->point_accepts_input = background_accepts_input;
wlr_scene_node_lower_to_bottom(&output->background->node);
}
else {
wlr_scene_buffer_set_buffer(output->background, server->background_buffer);
}
struct wlr_box box;
wlr_output_layout_get_box(server->output_layout, output->wlr_output, &box);
wlr_scene_node_set_position(&output->background->node, box.x, box.y);
wlr_scene_buffer_set_dest_size(output->background, box.width, box.height);
}
static void focus_toplevel(struct montis_toplevel *toplevel,
struct wlr_surface *surface)
{
/* Note: this function only deals with keyboard focus. */
if (toplevel == NULL) {
return;
}
struct montis_server *server = toplevel->server;
struct wlr_seat *seat = server->seat;
struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface;
if (prev_surface == surface) {
/* Don't re-focus an already focused surface. */
return;
}
if (prev_surface) {
/*
* Deactivate the previously focused surface. This lets the client know
* it no longer has focus and the client will repaint accordingly, e.g.
* stop displaying a caret.
*/
struct wlr_xdg_toplevel *prev_toplevel =
wlr_xdg_toplevel_try_from_wlr_surface(prev_surface);
if
|