blob: 97d2ab29e2566a51d62e075a2eccc954fe2c756c [file] [log] [blame]
/*
* Copyright (c) 2024 Amlogic, Inc. All rights reserved.
*
* This source code is subject to the terms and conditions defined in the
* file 'LICENSE' which is part of this source code package.
*
* Description:
*/
#include <libweston/libweston.h>
#include "aml-simpleshell.h"
#include <simpleshell/weston-simpleshell.h>
static struct weston_surface *
wstGetSurfaceFromSurfaceId( struct weston_compositor *compositor, int32_t surfaceId )
{
struct weston_surface *surface = NULL;
struct weston_surface_id *surface_id, *tmp;
wl_list_for_each_safe(surface_id, tmp, &compositor->surface_id_list, link) {
if (surface_id->id == surfaceId) {
surface = surface_id->surface;
break;
}
}
return surface;
}
static void simpleShellSetName( void* userData, uint32_t surfaceId, const char *name )
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
if (surface) {
if (surface->name) {
free(surface->name);
surface->name = NULL;
}
surface->name = strdup(name);
weston_log("set surfaceId %x name to %s\n", surfaceId, name );
}
}
static void simpleShellSetVisible( void* userData, uint32_t surfaceId, bool visible )
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
struct weston_view *view, *tmp;
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
if ( surface ) {
surface->visible= visible;
wl_list_for_each_safe(view, tmp, &surface->views, surface_link)
view->visible = visible;
if (surface->output)
weston_output_damage(surface->output);
}
}
static void simpleShellSetGeometry( void* userData, uint32_t surfaceId, int x, int y, int width, int height )
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
struct weston_output *output;
struct weston_view *view, *tmp;
weston_log("simpleShellSetGeometry: %d, %d, %d, %d\n", x, y, width, height);
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
if ( surface ) {
if (surface->output) {
surface->x = x;
surface->y = y;
surface->width = width;
surface->height = height;
wl_list_for_each_safe(view, tmp, &surface->views, surface_link)
weston_view_set_position(view, x, y);
weston_output_schedule_repaint(surface->output);
}
}
}
static void simpleShellSetOpacity( void* userData, uint32_t surfaceId, float opacity )
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
struct weston_view *view, *tmp;
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
if ( surface ) {
surface->opacity = opacity;
wl_list_for_each_safe(view, tmp, &surface->views, surface_link)
weston_view_opacity(view, opacity);
}
}
static void simpleShellSetZOrder( void* userData, uint32_t surfaceId, float zorder )
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
if ( surface )
surface->zorder= (int)(zorder * WESTON_ZORDER_MAX);
}
static void simpleShellSetFocus( void* userData, uint32_t surfaceId )
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
weston_log("%s: surfaceId %x\n", __FUNCTION__, surfaceId);
if ( !wl_list_empty(&compositor->seat_list) ) {
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
struct weston_seat *seat, *tmp;
if ( surface ) {
wl_list_for_each_safe(seat, tmp, &compositor->seat_list, link)
weston_keyboard_set_focus(seat->keyboard_state, surface);
} else {
weston_log("%s: failed to set focus - missing surface\n", __FUNCTION__);
}
} else {
weston_log("%s: failed to set focus - missing seat\n", __FUNCTION__);
}
}
static void simpleShellGetName( void* userData, uint32_t surfaceId, const char **name )
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
if ( surface ) {
*name= surface->name;
}
}
static struct weston_layer *
simpleShellGetLayer(struct weston_compositor *ec,
struct weston_surface *surface)
{
struct weston_layer *layer = NULL;
struct weston_view *view;
wl_list_for_each(layer, &ec->layer_list, link) {
wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
if (view->surface == surface)
return layer;
}
}
return NULL;
}
static void simpleShellGetStatus( void* userData, uint32_t surfaceId, bool *visible,
int *x, int *y, int *width, int *height,
float *opacity, float *zorder )
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
struct weston_view *view, *tmp;
struct weston_layer *layer;
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
if ( surface ) {
layer = simpleShellGetLayer(compositor, surface);
if (!layer || layer->position != WESTON_LAYER_POSITION_NORMAL) {
*width = 0;
*height = 0;
return;
}
*visible = surface->visible;
wl_list_for_each_safe(view, tmp, &surface->views, surface_link) {
*x = (int)view->geometry.x;
*y = (int)view->geometry.y;
}
*width = surface->width;
*height = surface->height;
*opacity = surface->opacity;
*zorder = (float)surface->zorder / WESTON_ZORDER_MAX;
}
}
static struct weston_key_intercept *
weston_create_key_intercept(uint32_t key_code,
uint32_t modifiers, struct wl_resource *resource,
struct weston_surface *surface)
{
struct weston_key_intercept *key = NULL;
key = zalloc(sizeof *key);
if (key) {
key->key_code = key_code;
key->flags = modifiers;
key->keyboard_object = resource;
key->surface = surface;
}
return key;
}
static struct wl_resource *
weston_get_resource_for_surface(struct weston_keyboard *keyboard,
struct weston_surface *surface)
{
struct wl_client *surfaceClient = NULL;
struct wl_list *focus_resource_list;
struct wl_resource *resource;
if (!keyboard || !surface || !surface->resource)
return NULL;
surfaceClient = wl_resource_get_client(surface->resource);
focus_resource_list = &keyboard->focus_resource_list;
wl_resource_for_each(resource, focus_resource_list) {
if (wl_resource_get_client(resource) == surfaceClient)
return resource;
}
wl_resource_for_each(resource, &keyboard->resource_list) {
if (wl_resource_get_client(resource) == surfaceClient)
return resource;
}
return NULL;
}
static void
weston_set_key_intercept(struct weston_keyboard *keyboard,
struct weston_surface *surface,
uint32_t keyCode, uint32_t modifiers)
{
struct wl_resource *resource;
bool sameKeyCodeAvailable = false;
struct weston_key_intercept *key_int;
resource = weston_get_resource_for_surface(keyboard, surface);
if (resource) {
wl_list_for_each(key_int, &keyboard->intercept_resource, link) {
if (key_int->key_code == keyCode &&
key_int->flags == modifiers &&
key_int->keyboard_object == resource) {
sameKeyCodeAvailable = true;
break;
}
}
if (!sameKeyCodeAvailable) {
key_int = weston_create_key_intercept(keyCode, modifiers, resource, surface);
if (key_int)
wl_list_insert(&keyboard->intercept_resource, &key_int->link);
}
} else {
weston_log("failed to find surface resource - missing surface");
}
}
static void simpleShellSetKeyIntercept( void* userData, uint32_t surfaceId, uint32_t keyCode, uint32_t modifiers)
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
struct weston_seat *seat, *tmp;
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
wl_list_for_each_safe(seat, tmp, &compositor->seat_list, link)
weston_set_key_intercept(seat->keyboard_state, surface, keyCode, modifiers);
}
static void
weston_remove_key_intercept(struct weston_keyboard *keyboard,
struct weston_surface *surface,
uint32_t keyCode, uint32_t modifiers)
{
struct wl_resource *resource;
struct weston_key_intercept *key_int, *tmp;
resource = weston_get_resource_for_surface(keyboard, surface);
if (resource) {
wl_list_for_each_safe(key_int, tmp, &keyboard->intercept_resource, link) {
if (key_int->key_code == keyCode &&
key_int->flags == modifiers &&
key_int->keyboard_object == resource) {
wl_list_remove(&key_int->link);
free(key_int);
break;
}
}
} else if (surface && !surface->resource) {
wl_list_for_each_safe(key_int, tmp, &keyboard->intercept_resource, link) {
if (key_int->surface == surface) {
wl_list_remove(&key_int->link);
free(key_int);
}
}
}
}
static void
simpleShellRemoveKeyIntercept( void* userData,
uint32_t surfaceId,
uint32_t keyCode,
uint32_t modifiers)
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
struct weston_seat *seat, *tmp;
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
wl_list_for_each_safe(seat, tmp, &compositor->seat_list, link)
weston_remove_key_intercept(seat->keyboard_state, surface, keyCode, modifiers);
}
static long long getCurrentTimeMillis(void)
{
struct timeval tv;
long long utcCurrentTimeMillis;
gettimeofday(&tv, 0);
utcCurrentTimeMillis = tv.tv_sec * 1000LL + (tv.tv_usec / 1000LL);
return utcCurrentTimeMillis;
}
static void
sendKeyToSurface(struct weston_keyboard *keyboard,
struct weston_surface *surface, uint32_t key)
{
struct wl_resource *resource;
struct wl_display *display = keyboard->seat->compositor->wl_display;
uint32_t serial;
uint32_t msecs;
resource = weston_get_resource_for_surface(keyboard, surface);
serial = wl_display_next_serial(display);
msecs = (uint32_t)getCurrentTimeMillis();
wl_keyboard_send_key(resource, serial, msecs, key, WL_KEYBOARD_KEY_STATE_PRESSED);
usleep(200 * 1000);
serial = wl_display_next_serial(display);
msecs = (uint32_t)getCurrentTimeMillis();
wl_keyboard_send_key(resource, serial, msecs, key, WL_KEYBOARD_KEY_STATE_RELEASED);
}
static void
simpleShellSendKey( void* userData,
uint32_t surfaceId,
uint32_t keyCode,
uint32_t modifiers)
{
struct weston_compositor *compositor = (struct weston_compositor *)userData;
struct weston_seat *seat, *tmp;
struct weston_surface *surface = wstGetSurfaceFromSurfaceId(compositor, surfaceId);
wl_list_for_each_safe(seat, tmp, &compositor->seat_list, link)
sendKeyToSurface(seat->keyboard_state, surface, keyCode);
}
struct wayland_simple_shell_callbacks simpleShellCallbacks = {
simpleShellSetName,
simpleShellSetVisible,
simpleShellSetGeometry,
simpleShellSetOpacity,
simpleShellSetZOrder,
simpleShellGetName,
simpleShellGetStatus,
simpleShellSetFocus,
NULL,
simpleShellSetKeyIntercept,
simpleShellRemoveKeyIntercept,
simpleShellSendKey,
};
WL_EXPORT int
load_simple_shell(struct weston_compositor *compositor,
void* (*load_module)(const char *, const char *))
{
struct wl_simple_shell* (*WstSimpleShellInit)( struct wl_display *display,
struct wayland_simple_shell_callbacks *callbacks,
void *userData );
WstSimpleShellInit = load_module("weston_simpleshell.so", "WstSimpleShellInit");
if (!WstSimpleShellInit)
return -1;
compositor->simple_shell = WstSimpleShellInit(compositor->wl_display,
&simpleShellCallbacks, compositor);
if (!compositor->simple_shell)
return -1;
return 0;
}
static uint32_t
weston_keyboard_get_modifiers(struct weston_keyboard *keyboard,
uint32_t mods_depressed,
uint32_t mods_latched,
uint32_t mods_locked, uint32_t group)
{
struct weston_xkb_info *xkb_info = keyboard->xkb_info;
uint32_t modifiers = 0;
if (mods_depressed & (1 << xkb_info->shift_mod))
modifiers |= 0x01;
if (mods_depressed & (1 << xkb_info->alt_mod))
modifiers |= 0x02;
if (mods_depressed & (1 << xkb_info->ctrl_mod))
modifiers |= 0x04;
if (mods_locked & (1 << xkb_info->caps_mod))
modifiers |= 0x08;
return modifiers;
}
WL_EXPORT bool
weston_keyboard_is_intercepted_keycode(struct weston_keyboard *keyboard,
uint32_t keycode, uint32_t mods_depressed,
uint32_t mods_latched,
uint32_t mods_locked, uint32_t group,
uint32_t serial, enum wl_keyboard_key_state state,
uint32_t msecs, bool modifier)
{
struct weston_key_intercept *key_int;
uint32_t modifiers;
bool ret = false;
wl_list_for_each(key_int, &keyboard->intercept_resource, link) {
if (modifier) {
modifiers = weston_keyboard_get_modifiers(keyboard, mods_depressed,
mods_latched, mods_locked, group);
if (key_int->key_code == keycode &&
key_int->flags == modifiers) {
wl_keyboard_send_modifiers(key_int->keyboard_object, serial,
mods_depressed, mods_latched,
mods_locked, group);
ret = true;
}
} else {
if (key_int->key_code == keycode && key_int->flags == 0) {
wl_keyboard_send_key(key_int->keyboard_object,
serial, msecs, keycode, state);
ret = true;
}
}
}
return ret;
}
WL_EXPORT void
weston_keyboard_add_key_info(struct weston_keyboard *keyboard,
struct wl_resource *resource, uint32_t key)
{
struct weston_key_info *info;
wl_list_for_each(info, &keyboard->key_info, link) {
if (info->resource == resource && info->key == key)
return;
}
info = zalloc(sizeof *info);
if (info) {
info->resource = resource;
info->key = key;
wl_list_insert(&keyboard->key_info, &info->link);
}
}
static struct weston_view *
weston_compositor_get_view_by_surface(struct weston_compositor *ec,
struct weston_surface *surface)
{
struct weston_layer *layer = NULL;
struct weston_view *view;
wl_list_for_each(layer, &ec->layer_list, link) {
wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
if (view->surface == surface)
return view;
}
}
return NULL;
}
static int
weston_compositor_set_zorder_by_surface(struct weston_compositor *ec,
struct weston_surface *surface)
{
struct weston_view *view, *ins_view;
struct weston_layer *layer;
ins_view = weston_compositor_get_view_by_surface(ec, surface);
if (!ins_view)
return -1;
layer = ins_view->layer_link.layer;
wl_list_remove(&ins_view->layer_link.link);
wl_list_for_each_reverse(view, &layer->view_list.link, layer_link.link) {
if (view->surface->zorder >= surface->zorder) {
weston_layer_entry_insert(&view->layer_link, &ins_view->layer_link);
return 0;
}
}
weston_layer_entry_insert(&layer->view_list, &ins_view->layer_link);
return 0;
}
WL_EXPORT void
weston_compositor_build_view_list_by_zorder(struct weston_compositor *compositor)
{
struct weston_surface_id *surface_id, *tmp;
wl_list_for_each_safe(surface_id, tmp, &compositor->surface_id_list, link)
weston_compositor_set_zorder_by_surface(compositor, surface_id->surface);
}
WL_EXPORT void
weston_surface_destroy_info_for_surface(struct weston_surface *surface)
{
struct weston_surface_id *surface_id = NULL;
struct weston_surface_id *surface_id_tmp = NULL;
wl_list_for_each_safe(surface_id, surface_id_tmp, &surface->compositor->surface_id_list, link) {
if (surface_id->surface == surface) {
wl_list_remove(&surface_id->link);
free(surface_id);
break;
}
}
if (surface->compositor->last_keyboard_focus == surface)
surface->compositor->last_keyboard_focus = NULL;
if (surface->name) {
free(surface->name);
surface->name = NULL;
}
}
static struct weston_surface_id *
compositor_create_surface_id(struct weston_surface *surface)
{
struct weston_surface_id *surface_id;
surface_id = zalloc(sizeof *surface_id);
if (surface_id == NULL)
return NULL;
surface_id->id = surface->surface_id;
surface_id->surface = surface;
return surface_id;
}
WL_EXPORT void
weston_compositor_add_surface_id(
struct weston_compositor *compositor,
struct weston_surface *surface)
{
struct weston_surface_id *surface_id;
surface_id = compositor_create_surface_id(surface);
if (surface_id == NULL)
return;
wl_list_insert(&compositor->surface_id_list, &surface_id->link);
}
WL_EXPORT void
weston_compositor_clear_surface_id(struct weston_compositor *compositor)
{
struct weston_surface_id *surface_id, *tmp;
wl_list_for_each_safe(surface_id, tmp, &compositor->surface_id_list, link) {
wl_list_remove(&surface_id->link);
free(surface_id);
}
}
WL_EXPORT void
weston_keyboard_clear_key_intercept(struct weston_keyboard *keyboard)
{
struct weston_key_intercept *key_int, *tmp;
wl_list_for_each_safe(key_int, tmp, &keyboard->intercept_resource, link) {
wl_list_remove(&key_int->link);
free(key_int);
}
}
WL_EXPORT void
weston_keyboard_clear_key_info_for_resource(
struct weston_keyboard *keyboard, struct wl_resource *resource)
{
struct weston_key_info *key_info, *tmp;
if (wl_list_empty(&keyboard->key_info))
return;
wl_list_for_each_safe(key_info, tmp, &keyboard->key_info, link) {
if (key_info->resource == resource) {
wl_list_remove(&key_info->link);
free(key_info);
break;
}
}
}
WL_EXPORT void
weston_keyboard_get_resource_and_key(struct weston_keyboard *keyboard,
struct wl_resource **resource, uint32_t *key)
{
struct weston_key_info *key_info, *tmp;
wl_list_for_each_safe(key_info, tmp, &keyboard->key_info, link) {
*resource = key_info->resource;
*key = key_info->key;
wl_list_remove(&key_info->link);
free(key_info);
break;
}
}