enlightenment/src/bin/e_comp_wl_surface.c

374 lines
9.6 KiB
C

#include "e.h"
#ifdef HAVE_WAYLAND_CLIENTS
# include "e_comp_wl.h"
# include "e_comp_wl_comp.h"
# include "e_comp_wl_output.h"
# include "e_comp_wl_input.h"
# include "e_comp_wl_shell.h"
# include "e_comp_wl_surface.h"
# include "e_comp_wl_buffer.h"
#endif
/* local function prototypes */
static void _e_comp_wl_surface_buffer_destroy_handle(struct wl_listener *listener, void *data __UNUSED__);
static void _e_comp_wl_surface_raise(Wayland_Surface *ws);
static void _e_comp_wl_surface_damage_rectangle(Wayland_Surface *ws, int32_t x, int32_t y, int32_t width, int32_t height);
static void _e_comp_wl_surface_frame_destroy_callback(struct wl_resource *resource);
Wayland_Surface *
e_comp_wl_surface_create(int32_t x, int32_t y, int32_t w, int32_t h)
{
Wayland_Surface *ws;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
if (!(ws = calloc(1, sizeof(Wayland_Surface)))) return NULL;
wl_list_init(&ws->link);
wl_list_init(&ws->buffer_link);
glGenTextures(1, &ws->texture);
glBindTexture(GL_TEXTURE_2D, ws->texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
ws->surface.resource.client = NULL;
ws->x = x;
ws->y = y;
ws->w = w;
ws->h = h;
ws->buffer = NULL;
ws->win = e_win_new(e_container_current_get(e_manager_current_get()));
e_win_borderless_set(ws->win, EINA_TRUE);
e_win_move_resize(ws->win, x, y, w, h);
pixman_region32_init(&ws->damage);
pixman_region32_init(&ws->opaque);
wl_list_init(&ws->frame_callbacks);
ws->buffer_destroy_listener.notify =
_e_comp_wl_surface_buffer_destroy_handle;
/* ws->transform = NULL; */
return ws;
}
void
e_comp_wl_surface_destroy(struct wl_client *client __UNUSED__, struct wl_resource *resource)
{
LOGFN(__FILE__, __LINE__, __FUNCTION__);
wl_resource_destroy(resource);
}
void
e_comp_wl_surface_attach(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *buffer_resource, int32_t x, int32_t y)
{
Wayland_Surface *ws;
struct wl_buffer *buffer;
struct wl_shell *shell;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
ws = resource->data;
buffer = buffer_resource->data;
shell = e_comp_wl_shell_get();
/* TODO: damage below ?? */
if (ws->buffer)
{
e_comp_wl_buffer_post_release(ws->buffer);
wl_list_remove(&ws->buffer_destroy_listener.link);
}
buffer->busy_count++;
ws->buffer = buffer;
wl_signal_add(&ws->buffer->resource.destroy_signal,
&ws->buffer_destroy_listener);
if (!ws->visual)
shell->shell.map(&shell->shell, ws, buffer->width, buffer->height);
else if ((x != 0) || (y != 0) ||
(ws->w != buffer->width) || (ws->h != buffer->height))
shell->shell.configure(&shell->shell, ws, ws->x + x, ws->y + y,
buffer->width, buffer->height);
e_comp_wl_buffer_attach(buffer, &ws->surface);
}
void
e_comp_wl_surface_damage(struct wl_client *client __UNUSED__, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
{
Wayland_Surface *ws;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
ws = resource->data;
_e_comp_wl_surface_damage_rectangle(ws, x, y, width, height);
}
void
e_comp_wl_surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback)
{
Wayland_Surface *ws;
Wayland_Frame_Callback *cb;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
ws = resource->data;
if (!(cb = malloc(sizeof(*cb))))
{
wl_resource_post_no_memory(resource);
return;
}
cb->resource.object.interface = &wl_callback_interface;
cb->resource.object.id = callback;
cb->resource.destroy = _e_comp_wl_surface_frame_destroy_callback;
cb->resource.client = client;
cb->resource.data = cb;
wl_client_add_resource(client, &cb->resource);
wl_list_insert(ws->frame_callbacks.prev, &cb->link);
}
void
e_comp_wl_surface_set_opaque_region(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *region_resource)
{
Wayland_Surface *ws;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
ws = resource->data;
pixman_region32_fini(&ws->opaque);
if (region_resource)
{
Wayland_Region *region;
region = region_resource->data;
pixman_region32_init_rect(&ws->opaque, 0, 0, ws->w, ws->h);
pixman_region32_intersect(&ws->opaque, &ws->opaque, &region->region);
}
else
pixman_region32_init(&ws->opaque);
}
void
e_comp_wl_surface_set_input_region(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *region_resource)
{
Wayland_Surface *ws;
Wayland_Input *input;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
ws = resource->data;
if (region_resource)
{
Wayland_Region *region;
region = region_resource->data;
pixman_region32_init_rect(&ws->input, 0, 0, ws->w, ws->h);
pixman_region32_intersect(&ws->input, &ws->input, &region->region);
}
else
pixman_region32_init_rect(&ws->input, 0, 0, ws->w, ws->h);
input = e_comp_wl_input_get();
e_comp_wl_comp_repick(&input->seat, e_comp_wl_time_get());
}
void
e_comp_wl_surface_commit(struct wl_client *client, struct wl_resource *resource)
{
Wayland_Surface *ws;
pixman_region32_t opaque;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
if (!(ws = resource->data)) return;
/* TODO: handle 'pending' ?? */
e_comp_wl_surface_configure(ws, ws->x, ws->y, ws->w, ws->h);
e_comp_wl_surface_damage_surface(ws);
pixman_region32_init_rect(&opaque, 0, 0, ws->w, ws->h);
pixman_region32_intersect(&opaque, &opaque, &ws->opaque);
if (!pixman_region32_equal(&opaque, &ws->opaque))
{
pixman_region32_copy(&ws->opaque, &opaque);
/* TODO: set dirty */
}
pixman_region32_fini(&opaque);
pixman_region32_fini(&ws->input);
pixman_region32_init_rect(&ws->input, 0, 0, ws->w, ws->h);
pixman_region32_intersect(&ws->input, &ws->input, &ws->input);
wl_list_init(&ws->frame_callbacks);
}
void
e_comp_wl_surface_destroy_surface(struct wl_resource *resource)
{
Wayland_Surface *ws;
Wayland_Input *input;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
ws = container_of(resource, Wayland_Surface, surface.resource);
/* TODO: damage below */
/* TODO: flush damage */
input = e_comp_wl_input_get();
if (ws->win)
e_object_del(E_OBJECT(ws->win));
wl_list_remove(&ws->link);
e_comp_wl_comp_repick(&input->seat, e_comp_wl_time_get());
if (ws->texture) glDeleteTextures(1, &ws->texture);
if (ws->buffer)
wl_list_remove(&ws->buffer_destroy_listener.link);
if (ws->image != EGL_NO_IMAGE_KHR)
{
Wayland_Compositor *comp;
comp = e_comp_wl_comp_get();
comp->destroy_image(comp->egl.display, ws->image);
}
wl_list_remove(&ws->buffer_link);
pixman_region32_fini(&ws->damage);
pixman_region32_fini(&ws->opaque);
free(ws);
}
void
e_comp_wl_surface_configure(Wayland_Surface *ws, int32_t x, int32_t y, int32_t width, int32_t height)
{
LOGFN(__FILE__, __LINE__, __FUNCTION__);
if (!ws) return;
/* TODO: damage below ? */
ws->x = x;
ws->y = y;
ws->w = width;
ws->h = height;
if (ws->win)
e_win_move_resize(ws->win, ws->x, ws->y, ws->w, ws->h);
if (!wl_list_empty(&ws->frame_callbacks))
{
Wayland_Output *output;
output = e_comp_wl_output_get();
wl_list_insert_list(output->frame_callbacks.prev,
&ws->frame_callbacks);
wl_list_init(&ws->frame_callbacks);
}
e_comp_wl_surface_damage_surface(ws);
pixman_region32_fini(&ws->opaque);
if (ws->visual == WAYLAND_RGB_VISUAL)
pixman_region32_init_rect(&ws->opaque, ws->x, ws->y, ws->w, ws->h);
else
pixman_region32_init(&ws->opaque);
}
void
e_comp_wl_surface_activate(Wayland_Surface *ws, Wayland_Input *wi, uint32_t timestamp __UNUSED__)
{
LOGFN(__FILE__, __LINE__, __FUNCTION__);
if (ws->win)
{
e_win_show(ws->win);
ws->win->border->borderless = EINA_TRUE;
}
_e_comp_wl_surface_raise(ws);
if (wi->seat.keyboard)
{
wl_keyboard_set_focus(wi->seat.keyboard, &ws->surface);
wl_data_device_set_keyboard_focus(&wi->seat);
}
/* TODO: emit activate signal ?? */
}
void
e_comp_wl_surface_damage_surface(Wayland_Surface *ws)
{
LOGFN(__FILE__, __LINE__, __FUNCTION__);
_e_comp_wl_surface_damage_rectangle(ws, 0, 0, ws->w, ws->h);
}
/* local functions */
static void
_e_comp_wl_surface_buffer_destroy_handle(struct wl_listener *listener, void *data __UNUSED__)
{
Wayland_Surface *ws;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
ws = container_of(listener, Wayland_Surface, buffer_destroy_listener);
ws->buffer = NULL;
}
static void
_e_comp_wl_surface_raise(Wayland_Surface *ws)
{
Wayland_Compositor *comp;
Wayland_Input *input;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
comp = e_comp_wl_comp_get();
input = e_comp_wl_input_get();
wl_list_remove(&ws->link);
wl_list_insert(&comp->surfaces, &ws->link);
e_comp_wl_comp_repick(&input->seat, e_comp_wl_time_get());
e_comp_wl_surface_damage_surface(ws);
}
static void
_e_comp_wl_surface_damage_rectangle(Wayland_Surface *ws, int32_t x, int32_t y, int32_t width, int32_t height)
{
LOGFN(__FILE__, __LINE__, __FUNCTION__);
pixman_region32_union_rect(&ws->damage, &ws->damage,
ws->x + x, ws->y + y, width, height);
}
static void
_e_comp_wl_surface_frame_destroy_callback(struct wl_resource *resource)
{
Wayland_Frame_Callback *cb;
LOGFN(__FILE__, __LINE__, __FUNCTION__);
cb = resource->data;
wl_list_remove(&cb->link);
free(cb);
}