FreeRDP/uwac/libuwac/uwac-window.c

851 lines
22 KiB
C
Raw Normal View History

/*
* Copyright © 2014 David FORT <contact@hardening-consulting.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <errno.h>
#include "uwac-priv.h"
#include "uwac-utils.h"
#include "uwac-os.h"
2022-02-16 13:10:02 +03:00
#include <uwac/config.h>
#define UWAC_INITIAL_BUFFERS 3
2016-10-19 12:05:12 +03:00
static int bppFromShmFormat(enum wl_shm_format format)
{
switch (format)
{
case WL_SHM_FORMAT_ARGB8888:
case WL_SHM_FORMAT_XRGB8888:
default:
return 4;
}
}
2016-10-19 12:05:12 +03:00
static void buffer_release(void* data, struct wl_buffer* buffer)
{
UwacBufferReleaseData* releaseData = data;
UwacBuffer* uwacBuffer = &releaseData->window->buffers[releaseData->bufferIdx];
uwacBuffer->used = false;
}
2019-11-06 17:24:51 +03:00
static const struct wl_buffer_listener buffer_listener = { buffer_release };
2019-11-20 13:30:14 +03:00
static void UwacWindowDestroyBuffers(UwacWindow* w)
2016-10-19 12:05:12 +03:00
{
int i;
2016-10-19 12:05:12 +03:00
for (i = 0; i < w->nbuffers; i++)
{
UwacBuffer* buffer = &w->buffers[i];
#ifdef UWAC_HAVE_PIXMAN_REGION
pixman_region32_fini(&buffer->damage);
#else
region16_uninit(&buffer->damage);
#endif
UwacBufferReleaseData* releaseData =
(UwacBufferReleaseData*)wl_buffer_get_user_data(buffer->wayland_buffer);
wl_buffer_destroy(buffer->wayland_buffer);
free(releaseData);
munmap(buffer->data, buffer->size);
}
w->nbuffers = 0;
free(w->buffers);
w->buffers = NULL;
}
2019-11-20 13:30:14 +03:00
static int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32_t width,
uint32_t height, enum wl_shm_format format);
2019-11-06 17:24:51 +03:00
static void xdg_handle_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel,
int32_t width, int32_t height, struct wl_array* states)
{
2016-10-19 12:05:12 +03:00
UwacWindow* window = (UwacWindow*)data;
UwacConfigureEvent* event;
int ret, surfaceState;
enum xdg_toplevel_state* state;
surfaceState = 0;
2016-10-19 12:05:12 +03:00
wl_array_for_each(state, states)
{
switch (*state)
{
case XDG_TOPLEVEL_STATE_MAXIMIZED:
2016-10-19 12:05:12 +03:00
surfaceState |= UWAC_WINDOW_MAXIMIZED;
break;
case XDG_TOPLEVEL_STATE_FULLSCREEN:
2016-10-19 12:05:12 +03:00
surfaceState |= UWAC_WINDOW_FULLSCREEN;
break;
case XDG_TOPLEVEL_STATE_ACTIVATED:
2016-10-19 12:05:12 +03:00
surfaceState |= UWAC_WINDOW_ACTIVATED;
break;
case XDG_TOPLEVEL_STATE_RESIZING:
2016-10-19 12:05:12 +03:00
surfaceState |= UWAC_WINDOW_RESIZING;
break;
default:
break;
}
}
window->surfaceStates = surfaceState;
2016-10-19 12:05:12 +03:00
event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
2016-10-19 12:05:12 +03:00
if (!event)
{
assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
"failed to allocate a configure event\n"));
2019-01-22 20:09:53 +03:00
return;
}
event->window = window;
event->states = surfaceState;
2016-10-19 12:05:12 +03:00
2022-06-23 08:57:38 +03:00
if ((width > 0 && height > 0) && (width != window->width || height != window->height))
2016-10-19 12:05:12 +03:00
{
event->width = width;
event->height = height;
UwacWindowDestroyBuffers(window);
window->width = width;
window->stride = width * bppFromShmFormat(window->format);
window->height = height;
ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height,
2016-10-19 12:05:12 +03:00
width, height, window->format);
if (ret != UWAC_SUCCESS)
{
2019-11-06 17:24:51 +03:00
assert(
uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
2020-06-16 14:54:12 +03:00
window->drawingBufferIdx = window->pendingBufferIdx = -1;
2019-01-22 20:09:53 +03:00
return;
}
2016-10-19 12:05:12 +03:00
2020-06-16 14:54:12 +03:00
window->drawingBufferIdx = 0;
if (window->pendingBufferIdx != -1)
window->pendingBufferIdx = window->drawingBufferIdx;
2016-10-19 12:05:12 +03:00
}
else
{
event->width = window->width;
event->height = window->height;
}
}
2019-11-06 17:24:51 +03:00
static void xdg_handle_toplevel_close(void* data, struct xdg_toplevel* xdg_toplevel)
{
2016-10-19 12:05:12 +03:00
UwacCloseEvent* event;
UwacWindow* window = (UwacWindow*)data;
event = (UwacCloseEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CLOSE);
if (!event)
{
assert(uwacErrorHandler(window->display, UWAC_ERROR_INTERNAL,
"failed to allocate a close event\n"));
return;
}
event->window = window;
}
2019-11-06 17:24:51 +03:00
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
xdg_handle_toplevel_configure,
xdg_handle_toplevel_close,
};
2019-11-06 17:24:51 +03:00
static void xdg_handle_surface_configure(void* data, struct xdg_surface* xdg_surface,
uint32_t serial)
{
xdg_surface_ack_configure(xdg_surface, serial);
}
2019-11-06 17:24:51 +03:00
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_handle_surface_configure,
};
#if BUILD_IVI
2019-11-06 17:24:51 +03:00
static void ivi_handle_configure(void* data, struct ivi_surface* surface, int32_t width,
int32_t height)
{
2016-10-19 12:05:12 +03:00
UwacWindow* window = (UwacWindow*)data;
UwacConfigureEvent* event;
int ret;
2016-10-19 12:05:12 +03:00
event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
2016-10-19 12:05:12 +03:00
if (!event)
{
assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
"failed to allocate a configure event\n"));
return;
}
event->window = window;
event->states = 0;
2016-10-19 12:05:12 +03:00
if (width && height)
{
event->width = width;
event->height = height;
UwacWindowDestroyBuffers(window);
window->width = width;
window->stride = width * bppFromShmFormat(window->format);
window->height = height;
ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height,
2016-10-19 12:05:12 +03:00
width, height, window->format);
if (ret != UWAC_SUCCESS)
{
2019-11-06 17:24:51 +03:00
assert(
uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
2020-06-16 14:54:12 +03:00
window->drawingBufferIdx = window->pendingBufferIdx = -1;
return;
}
2016-10-19 12:05:12 +03:00
2020-06-16 14:54:12 +03:00
window->drawingBufferIdx = 0;
if (window->pendingBufferIdx != -1)
window->pendingBufferIdx = window->drawingBufferIdx;
2016-10-19 12:05:12 +03:00
}
else
{
event->width = window->width;
event->height = window->height;
}
}
2019-11-06 17:24:51 +03:00
static const struct ivi_surface_listener ivi_surface_listener = {
ivi_handle_configure,
};
#endif
2019-11-20 13:30:14 +03:00
static void shell_ping(void* data, struct wl_shell_surface* surface, uint32_t serial)
{
wl_shell_surface_pong(surface, serial);
}
2019-11-20 13:30:14 +03:00
static void shell_configure(void* data, struct wl_shell_surface* surface, uint32_t edges,
int32_t width, int32_t height)
{
2016-10-19 12:05:12 +03:00
UwacWindow* window = (UwacWindow*)data;
UwacConfigureEvent* event;
int ret;
2016-10-19 12:05:12 +03:00
event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
2016-10-19 12:05:12 +03:00
if (!event)
{
assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
"failed to allocate a configure event\n"));
return;
}
event->window = window;
event->states = 0;
2016-10-19 12:05:12 +03:00
if (width && height)
{
event->width = width;
event->height = height;
UwacWindowDestroyBuffers(window);
window->width = width;
window->stride = width * bppFromShmFormat(window->format);
window->height = height;
ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height,
2016-10-19 12:05:12 +03:00
width, height, window->format);
if (ret != UWAC_SUCCESS)
{
2019-11-06 17:24:51 +03:00
assert(
uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
2020-06-16 14:54:12 +03:00
window->drawingBufferIdx = window->pendingBufferIdx = -1;
return;
}
2016-10-19 12:05:12 +03:00
2020-06-16 14:54:12 +03:00
window->drawingBufferIdx = 0;
if (window->pendingBufferIdx != -1)
window->pendingBufferIdx = window->drawingBufferIdx;
2016-10-19 12:05:12 +03:00
}
else
{
event->width = window->width;
event->height = window->height;
}
}
2019-11-20 13:30:14 +03:00
static void shell_popup_done(void* data, struct wl_shell_surface* surface)
{
}
2019-11-06 17:24:51 +03:00
static const struct wl_shell_surface_listener shell_listener = { shell_ping, shell_configure,
shell_popup_done };
2016-10-19 12:05:12 +03:00
int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32_t width,
uint32_t height, enum wl_shm_format format)
{
int ret = UWAC_SUCCESS;
2016-10-19 12:05:12 +03:00
UwacBuffer* newBuffers;
int i, fd;
2016-10-19 12:05:12 +03:00
void* data;
struct wl_shm_pool* pool;
size_t pagesize = sysconf(_SC_PAGESIZE);
newBuffers = xrealloc(w->buffers, (w->nbuffers + nbuffers) * sizeof(UwacBuffer));
2016-10-19 12:05:12 +03:00
if (!newBuffers)
return UWAC_ERROR_NOMEMORY;
/* round up to a multiple of PAGESIZE to page align data for each buffer */
allocSize = (allocSize + pagesize - 1) & ~(pagesize - 1);
w->buffers = newBuffers;
memset(w->buffers + w->nbuffers, 0, sizeof(UwacBuffer) * nbuffers);
fd = uwac_create_anonymous_file(1ull * allocSize * nbuffers);
2016-10-19 12:05:12 +03:00
if (fd < 0)
{
return UWAC_ERROR_INTERNAL;
}
data = mmap(NULL, 1ull * allocSize * nbuffers, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2016-10-19 12:05:12 +03:00
if (data == MAP_FAILED)
{
ret = UWAC_ERROR_NOMEMORY;
goto error_mmap;
}
pool = wl_shm_create_pool(w->display->shm, fd, allocSize * nbuffers);
2016-10-19 12:05:12 +03:00
if (!pool)
{
munmap(data, 1ull * allocSize * nbuffers);
2016-02-25 02:41:19 +03:00
ret = UWAC_ERROR_NOMEMORY;
goto error_mmap;
}
2016-10-19 12:05:12 +03:00
for (i = 0; i < nbuffers; i++)
{
int bufferIdx = w->nbuffers + i;
UwacBuffer* buffer = &w->buffers[bufferIdx];
#ifdef UWAC_HAVE_PIXMAN_REGION
pixman_region32_init(&buffer->damage);
#else
region16_init(&buffer->damage);
#endif
2022-12-09 16:35:03 +03:00
buffer->data = &((char*)data)[allocSize * i];
buffer->size = allocSize;
2019-11-06 17:24:51 +03:00
buffer->wayland_buffer =
wl_shm_pool_create_buffer(pool, allocSize * i, width, height, w->stride, format);
UwacBufferReleaseData* listener_data = xmalloc(sizeof(UwacBufferReleaseData));
listener_data->window = w;
listener_data->bufferIdx = bufferIdx;
wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, listener_data);
}
wl_shm_pool_destroy(pool);
w->nbuffers += nbuffers;
error_mmap:
close(fd);
return ret;
}
2021-06-18 11:01:33 +03:00
static UwacBuffer* UwacWindowFindFreeBuffer(UwacWindow* w, ssize_t* index)
2016-10-19 12:05:12 +03:00
{
2021-06-18 11:01:33 +03:00
ssize_t i;
2020-06-16 14:54:12 +03:00
int ret;
if (index)
*index = -1;
2016-10-19 12:05:12 +03:00
for (i = 0; i < w->nbuffers; i++)
{
if (!w->buffers[i].used)
{
w->buffers[i].used = true;
2020-06-16 14:54:12 +03:00
if (index)
*index = i;
return &w->buffers[i];
}
}
ret = UwacWindowShmAllocBuffers(w, 2, w->stride * w->height, w->width, w->height, w->format);
2016-10-19 12:05:12 +03:00
if (ret != UWAC_SUCCESS)
{
w->display->last_error = ret;
return NULL;
}
w->buffers[i].used = true;
2020-06-16 14:54:12 +03:00
if (index)
*index = i;
return &w->buffers[i];
}
2019-11-06 17:24:51 +03:00
static UwacReturnCode UwacWindowSetDecorations(UwacWindow* w)
{
if (!w || !w->display)
return UWAC_ERROR_INTERNAL;
2019-11-06 17:24:51 +03:00
if (w->display->deco_manager)
{
w->deco = zxdg_decoration_manager_v1_get_toplevel_decoration(w->display->deco_manager,
w->xdg_toplevel);
if (!w->deco)
{
uwacErrorHandler(w->display, UWAC_NOT_FOUND,
"Current window manager does not allow decorating with SSD");
}
else
2019-11-06 17:24:51 +03:00
zxdg_toplevel_decoration_v1_set_mode(w->deco,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
2019-11-06 17:24:51 +03:00
else if (w->display->kde_deco_manager)
{
w->kde_deco =
org_kde_kwin_server_decoration_manager_create(w->display->kde_deco_manager, w->surface);
if (!w->kde_deco)
{
uwacErrorHandler(w->display, UWAC_NOT_FOUND,
"Current window manager does not allow decorating with SSD");
}
else
2019-11-06 17:24:51 +03:00
org_kde_kwin_server_decoration_request_mode(w->kde_deco,
ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER);
}
return UWAC_SUCCESS;
}
2016-10-19 12:05:12 +03:00
UwacWindow* UwacCreateWindowShm(UwacDisplay* display, uint32_t width, uint32_t height,
enum wl_shm_format format)
{
UwacWindow* w;
int allocSize, ret;
2016-10-19 12:05:12 +03:00
if (!display)
{
return NULL;
}
w = xzalloc(sizeof(*w));
2016-10-19 12:05:12 +03:00
if (!w)
{
display->last_error = UWAC_ERROR_NOMEMORY;
return NULL;
}
w->display = display;
w->format = format;
w->width = width;
w->height = height;
w->stride = width * bppFromShmFormat(format);
allocSize = w->stride * height;
ret = UwacWindowShmAllocBuffers(w, UWAC_INITIAL_BUFFERS, allocSize, width, height, format);
2016-10-19 12:05:12 +03:00
if (ret != UWAC_SUCCESS)
{
display->last_error = ret;
goto out_error_free;
}
w->buffers[0].used = true;
2020-06-16 14:54:12 +03:00
w->drawingBufferIdx = 0;
w->pendingBufferIdx = -1;
w->surface = wl_compositor_create_surface(display->compositor);
2016-10-19 12:05:12 +03:00
if (!w->surface)
{
display->last_error = UWAC_ERROR_NOMEMORY;
goto out_error_surface;
}
2016-10-19 12:05:12 +03:00
wl_surface_set_user_data(w->surface, w);
#if BUILD_IVI
uint32_t ivi_surface_id = 1;
char* env = getenv("IVI_SURFACE_ID");
if (env)
{
unsigned long val;
char* endp;
errno = 0;
val = strtoul(env, &endp, 10);
if (!errno && val != 0 && val != UINT32_MAX)
ivi_surface_id = val;
}
if (display->ivi_application)
{
2022-06-23 08:57:38 +03:00
w->ivi_surface =
ivi_application_surface_create(display->ivi_application, ivi_surface_id, w->surface);
assert(w->ivi_surface);
ivi_surface_add_listener(w->ivi_surface, &ivi_surface_listener, w);
2022-06-23 08:57:38 +03:00
}
else
#endif
#if BUILD_FULLSCREEN_SHELL
2022-06-23 08:57:38 +03:00
if (display->fullscreen_shell)
{
zwp_fullscreen_shell_v1_present_surface(display->fullscreen_shell, w->surface,
2022-06-23 08:57:38 +03:00
ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER,
NULL);
}
else
#endif
2022-06-23 08:57:38 +03:00
if (display->xdg_base)
2016-10-19 12:05:12 +03:00
{
w->xdg_surface = xdg_wm_base_get_xdg_surface(display->xdg_base, w->surface);
2016-10-19 12:05:12 +03:00
if (!w->xdg_surface)
{
display->last_error = UWAC_ERROR_NOMEMORY;
goto out_error_shell;
}
xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
if (!w->xdg_toplevel)
{
display->last_error = UWAC_ERROR_NOMEMORY;
goto out_error_shell;
}
assert(w->xdg_surface);
xdg_toplevel_add_listener(w->xdg_toplevel, &xdg_toplevel_listener, w);
wl_surface_commit(w->surface);
wl_display_roundtrip(w->display->display);
2016-10-19 12:05:12 +03:00
}
else
{
w->shell_surface = wl_shell_get_shell_surface(display->shell, w->surface);
assert(w->shell_surface);
wl_shell_surface_add_listener(w->shell_surface, &shell_listener, w);
wl_shell_surface_set_toplevel(w->shell_surface);
}
wl_list_insert(display->windows.prev, &w->link);
display->last_error = UWAC_SUCCESS;
UwacWindowSetDecorations(w);
return w;
out_error_shell:
wl_surface_destroy(w->surface);
out_error_surface:
UwacWindowDestroyBuffers(w);
out_error_free:
free(w);
return NULL;
}
2016-10-19 12:05:12 +03:00
UwacReturnCode UwacDestroyWindow(UwacWindow** pwindow)
{
UwacWindow* w;
assert(pwindow);
w = *pwindow;
UwacWindowDestroyBuffers(w);
2019-01-22 17:45:15 +03:00
if (w->deco)
zxdg_toplevel_decoration_v1_destroy(w->deco);
if (w->kde_deco)
org_kde_kwin_server_decoration_destroy(w->kde_deco);
if (w->xdg_surface)
xdg_surface_destroy(w->xdg_surface);
2016-10-19 12:05:12 +03:00
#if BUILD_IVI
2016-10-19 12:05:12 +03:00
if (w->ivi_surface)
ivi_surface_destroy(w->ivi_surface);
2016-10-19 12:05:12 +03:00
#endif
if (w->opaque_region)
wl_region_destroy(w->opaque_region);
if (w->input_region)
wl_region_destroy(w->input_region);
wl_surface_destroy(w->surface);
wl_list_remove(&w->link);
free(w);
*pwindow = NULL;
return UWAC_SUCCESS;
}
2016-10-19 12:05:12 +03:00
UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
2019-11-06 17:24:51 +03:00
uint32_t height)
{
assert(window);
if (window->opaque_region)
wl_region_destroy(window->opaque_region);
window->opaque_region = wl_compositor_create_region(window->display->compositor);
2016-10-19 12:05:12 +03:00
if (!window->opaque_region)
return UWAC_ERROR_NOMEMORY;
wl_region_add(window->opaque_region, x, y, width, height);
wl_surface_set_opaque_region(window->surface, window->opaque_region);
return UWAC_SUCCESS;
}
2016-10-19 12:05:12 +03:00
UwacReturnCode UwacWindowSetInputRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
uint32_t height)
{
assert(window);
if (window->input_region)
wl_region_destroy(window->input_region);
window->input_region = wl_compositor_create_region(window->display->compositor);
2016-10-19 12:05:12 +03:00
if (!window->input_region)
return UWAC_ERROR_NOMEMORY;
wl_region_add(window->input_region, x, y, width, height);
wl_surface_set_input_region(window->surface, window->input_region);
return UWAC_SUCCESS;
}
2016-10-19 12:05:12 +03:00
void* UwacWindowGetDrawingBuffer(UwacWindow* window)
{
2020-06-16 14:54:12 +03:00
UwacBuffer* buffer;
if (window->drawingBufferIdx < 0)
return NULL;
buffer = &window->buffers[window->drawingBufferIdx];
if (!buffer)
return NULL;
return buffer->data;
}
2016-10-19 12:05:12 +03:00
static void frame_done_cb(void* data, struct wl_callback* callback, uint32_t time);
2019-11-06 17:24:51 +03:00
static const struct wl_callback_listener frame_listener = { frame_done_cb };
#ifdef UWAC_HAVE_PIXMAN_REGION
static void damage_surface(UwacWindow* window, UwacBuffer* buffer)
2016-10-19 12:05:12 +03:00
{
2021-06-18 11:01:33 +03:00
int nrects, i;
const pixman_box32_t* box = pixman_region32_rectangles(&buffer->damage, &nrects);
2016-10-19 12:05:12 +03:00
for (i = 0; i < nrects; i++, box++)
2019-11-06 17:24:51 +03:00
wl_surface_damage(window->surface, box->x1, box->y1, (box->x2 - box->x1),
(box->y2 - box->y1));
2016-10-19 12:05:12 +03:00
pixman_region32_clear(&buffer->damage);
}
#else
static void damage_surface(UwacWindow* window, UwacBuffer* buffer)
{
2021-06-18 11:01:33 +03:00
uint32_t nrects, i;
const RECTANGLE_16* box = region16_rects(&buffer->damage, &nrects);
2016-10-19 12:05:12 +03:00
for (i = 0; i < nrects; i++, box++)
2016-10-19 12:05:12 +03:00
wl_surface_damage(window->surface, box->left, box->top, (box->right - box->left),
(box->bottom - box->top));
region16_clear(&buffer->damage);
}
#endif
static void UwacSubmitBufferPtr(UwacWindow* window, UwacBuffer* buffer)
{
wl_surface_attach(window->surface, buffer->wayland_buffer, 0, 0);
damage_surface(window, buffer);
struct wl_callback* frame_callback = wl_surface_frame(window->surface);
wl_callback_add_listener(frame_callback, &frame_listener, window);
wl_surface_commit(window->surface);
2019-07-25 19:56:28 +03:00
buffer->dirty = false;
}
2016-10-19 12:05:12 +03:00
static void frame_done_cb(void* data, struct wl_callback* callback, uint32_t time)
{
UwacWindow* window = (UwacWindow*)data;
UwacFrameDoneEvent* event;
wl_callback_destroy(callback);
2020-06-16 14:54:12 +03:00
window->pendingBufferIdx = -1;
2016-10-19 12:05:12 +03:00
event = (UwacFrameDoneEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_FRAME_DONE);
if (event)
event->window = window;
}
#ifdef UWAC_HAVE_PIXMAN_REGION
2016-10-19 12:05:12 +03:00
UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
uint32_t height)
{
2021-06-18 11:01:33 +03:00
UwacBuffer* buf;
if (window->drawingBufferIdx < 0)
return UWAC_ERROR_INTERNAL;
buf = &window->buffers[window->drawingBufferIdx];
2019-07-25 19:56:28 +03:00
if (!pixman_region32_union_rect(&buf->damage, &buf->damage, x, y, width, height))
return UWAC_ERROR_INTERNAL;
2019-07-25 19:56:28 +03:00
buf->dirty = true;
return UWAC_SUCCESS;
}
#else
UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
uint32_t height)
{
RECTANGLE_16 box;
2020-06-16 14:54:12 +03:00
UwacBuffer* buf;
2016-10-19 12:05:12 +03:00
box.left = x;
box.top = y;
box.right = x + width;
box.bottom = y + height;
2020-06-16 14:54:12 +03:00
if (window->drawingBufferIdx < 0)
return UWAC_ERROR_INTERNAL;
buf = &window->buffers[window->drawingBufferIdx];
if (!buf)
return UWAC_ERROR_INTERNAL;
2019-07-25 19:56:28 +03:00
if (!region16_union_rect(&buf->damage, &buf->damage, &box))
return UWAC_ERROR_INTERNAL;
2019-07-25 19:56:28 +03:00
buf->dirty = true;
return UWAC_SUCCESS;
}
#endif
2019-11-06 17:24:51 +03:00
UwacReturnCode UwacWindowGetDrawingBufferGeometry(UwacWindow* window, UwacSize* geometry,
size_t* stride)
{
2020-06-16 14:54:12 +03:00
if (!window || (window->drawingBufferIdx < 0))
return UWAC_ERROR_INTERNAL;
if (geometry)
{
geometry->width = window->width;
geometry->height = window->height;
}
if (stride)
*stride = window->stride;
return UWAC_SUCCESS;
}
2016-10-19 12:05:12 +03:00
UwacReturnCode UwacWindowSubmitBuffer(UwacWindow* window, bool copyContentForNextFrame)
{
UwacBuffer* currentDrawingBuffer;
UwacBuffer* nextDrawingBuffer;
UwacBuffer* pendingBuffer;
2020-06-16 14:54:12 +03:00
if (window->drawingBufferIdx < 0)
return UWAC_ERROR_INTERNAL;
currentDrawingBuffer = &window->buffers[window->drawingBufferIdx];
if ((window->pendingBufferIdx >= 0) || !currentDrawingBuffer->dirty)
return UWAC_SUCCESS;
2020-06-16 14:54:12 +03:00
window->pendingBufferIdx = window->drawingBufferIdx;
nextDrawingBuffer = UwacWindowFindFreeBuffer(window, &window->drawingBufferIdx);
pendingBuffer = &window->buffers[window->pendingBufferIdx];
2016-10-19 12:05:12 +03:00
if ((!nextDrawingBuffer) || (window->drawingBufferIdx < 0))
return UWAC_ERROR_NOMEMORY;
2016-10-19 12:05:12 +03:00
if (copyContentForNextFrame)
2021-01-25 12:06:01 +03:00
memcpy(nextDrawingBuffer->data, pendingBuffer->data,
1ull * window->stride * window->height);
UwacSubmitBufferPtr(window, pendingBuffer);
return UWAC_SUCCESS;
}
2016-10-19 12:05:12 +03:00
UwacReturnCode UwacWindowGetGeometry(UwacWindow* window, UwacSize* geometry)
{
assert(window);
assert(geometry);
geometry->width = window->width;
geometry->height = window->height;
return UWAC_SUCCESS;
}
2016-10-19 12:05:12 +03:00
UwacReturnCode UwacWindowSetFullscreenState(UwacWindow* window, UwacOutput* output,
2019-11-06 17:24:51 +03:00
bool isFullscreen)
2016-10-19 12:05:12 +03:00
{
if (window->xdg_toplevel)
2016-10-19 12:05:12 +03:00
{
if (isFullscreen)
{
xdg_toplevel_set_fullscreen(window->xdg_toplevel, output ? output->output : NULL);
2016-10-19 12:05:12 +03:00
}
else
{
xdg_toplevel_unset_fullscreen(window->xdg_toplevel);
}
}
else if (window->shell_surface)
{
if (isFullscreen)
{
wl_shell_surface_set_fullscreen(window->shell_surface,
2019-11-06 17:24:51 +03:00
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0,
output ? output->output : NULL);
}
else
{
wl_shell_surface_set_toplevel(window->shell_surface);
}
}
2016-10-19 12:05:12 +03:00
return UWAC_SUCCESS;
}
2016-10-19 12:05:12 +03:00
void UwacWindowSetTitle(UwacWindow* window, const char* name)
{
if (window->xdg_toplevel)
xdg_toplevel_set_title(window->xdg_toplevel, name);
else if (window->shell_surface)
wl_shell_surface_set_title(window->shell_surface, name);
}
2021-11-12 13:57:03 +03:00
void UwacWindowSetAppId(UwacWindow* window, const char* app_id)
{
if (window->xdg_toplevel)
xdg_toplevel_set_app_id(window->xdg_toplevel, app_id);
}