| /* |
| * 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; |
| } |
| } |