2020-04-21 18:23:37 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2010-2012 Intel Corporation
|
|
|
|
* Copyright 2013 Raspberry Pi Foundation
|
|
|
|
* Copyright 2011-2012,2020 Collabora, Ltd.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
* Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <linux/input.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "kiosk-shell.h"
|
|
|
|
#include "kiosk-shell-grab.h"
|
2023-12-15 15:20:18 +03:00
|
|
|
#include "frontend/weston.h"
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
#include "libweston/libweston.h"
|
2020-04-21 18:23:37 +03:00
|
|
|
#include "shared/helpers.h"
|
2022-11-22 14:28:57 +03:00
|
|
|
#include <libweston/shell-utils.h>
|
2020-04-21 18:23:37 +03:00
|
|
|
|
2021-03-24 13:47:07 +03:00
|
|
|
#include <libweston/xwayland-api.h>
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
static struct kiosk_shell_surface *
|
|
|
|
get_kiosk_shell_surface(struct weston_surface *surface)
|
|
|
|
{
|
|
|
|
struct weston_desktop_surface *desktop_surface =
|
|
|
|
weston_surface_get_desktop_surface(surface);
|
|
|
|
|
|
|
|
if (desktop_surface)
|
|
|
|
return weston_desktop_surface_get_user_data(desktop_surface);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_seat_handle_destroy(struct wl_listener *listener, void *data);
|
|
|
|
|
|
|
|
static struct kiosk_shell_seat *
|
|
|
|
get_kiosk_shell_seat(struct weston_seat *seat)
|
|
|
|
{
|
|
|
|
struct wl_listener *listener;
|
|
|
|
|
2021-11-02 14:41:30 +03:00
|
|
|
if (!seat)
|
|
|
|
return NULL;
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
listener = wl_signal_get(&seat->destroy_signal,
|
|
|
|
kiosk_shell_seat_handle_destroy);
|
2021-11-02 14:41:30 +03:00
|
|
|
|
|
|
|
if (!listener)
|
|
|
|
return NULL;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
return container_of(listener,
|
|
|
|
struct kiosk_shell_seat, seat_destroy_listener);
|
|
|
|
}
|
|
|
|
|
2021-03-05 22:58:40 +03:00
|
|
|
|
|
|
|
static struct weston_seat *
|
|
|
|
get_kiosk_shell_first_seat(struct kiosk_shell *shell)
|
|
|
|
{
|
|
|
|
struct wl_list *node;
|
|
|
|
struct weston_compositor *compositor = shell->compositor;
|
|
|
|
|
|
|
|
if (wl_list_empty(&compositor->seat_list))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
node = compositor->seat_list.next;
|
|
|
|
return container_of(node, struct weston_seat, link);
|
|
|
|
}
|
|
|
|
|
2021-03-24 13:47:07 +03:00
|
|
|
static void
|
|
|
|
transform_handler(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct weston_surface *surface = data;
|
|
|
|
struct kiosk_shell_surface *shsurf = get_kiosk_shell_surface(surface);
|
|
|
|
const struct weston_xwayland_surface_api *api;
|
|
|
|
|
|
|
|
if (!shsurf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
api = shsurf->shell->xwayland_surface_api;
|
|
|
|
if (!api) {
|
|
|
|
api = weston_xwayland_surface_get_api(shsurf->shell->compositor);
|
|
|
|
shsurf->shell->xwayland_surface_api = api;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!api || !api->is_xwayland_surface(surface))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!weston_view_is_mapped(shsurf->view))
|
|
|
|
return;
|
|
|
|
|
2022-02-04 02:47:41 +03:00
|
|
|
api->send_position(surface,
|
|
|
|
shsurf->view->geometry.pos_offset.x,
|
|
|
|
shsurf->view->geometry.pos_offset.y);
|
2021-03-24 13:47:07 +03:00
|
|
|
}
|
|
|
|
|
2023-08-03 15:52:02 +03:00
|
|
|
static const char *
|
|
|
|
xwayland_get_xwayland_name(struct kiosk_shell_surface *shsurf, enum window_atom_type type)
|
|
|
|
{
|
|
|
|
const struct weston_xwayland_surface_api *api;
|
|
|
|
struct weston_surface *surface;
|
|
|
|
|
|
|
|
api = shsurf->shell->xwayland_surface_api;
|
|
|
|
if (!api) {
|
|
|
|
api = weston_xwayland_surface_get_api(shsurf->shell->compositor);
|
|
|
|
shsurf->shell->xwayland_surface_api = api;
|
|
|
|
}
|
|
|
|
|
|
|
|
surface = weston_desktop_surface_get_surface(shsurf->desktop_surface);
|
|
|
|
if (!api || !api->is_xwayland_surface(surface))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return api->get_xwayland_window_name(surface, type);
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
/*
|
|
|
|
* kiosk_shell_surface
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_surface_set_output(struct kiosk_shell_surface *shsurf,
|
|
|
|
struct weston_output *output);
|
|
|
|
static void
|
|
|
|
kiosk_shell_surface_set_parent(struct kiosk_shell_surface *shsurf,
|
|
|
|
struct kiosk_shell_surface *parent);
|
2023-05-27 01:01:21 +03:00
|
|
|
static void
|
|
|
|
kiosk_shell_output_set_active_surface_tree(struct kiosk_shell_output *shoutput,
|
|
|
|
struct kiosk_shell_surface *shroot);
|
2023-06-06 02:30:35 +03:00
|
|
|
static void
|
|
|
|
kiosk_shell_output_raise_surface_subtree(struct kiosk_shell_output *shoutput,
|
|
|
|
struct kiosk_shell_surface *shroot);
|
2023-05-27 01:01:21 +03:00
|
|
|
static struct kiosk_shell_output *
|
|
|
|
kiosk_shell_find_shell_output(struct kiosk_shell *shell,
|
|
|
|
struct weston_output *output);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_surface_notify_parent_destroy(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
container_of(listener,
|
|
|
|
struct kiosk_shell_surface, parent_destroy_listener);
|
|
|
|
|
|
|
|
kiosk_shell_surface_set_parent(shsurf, shsurf->parent->parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_surface_notify_output_destroy(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
container_of(listener,
|
|
|
|
struct kiosk_shell_surface, output_destroy_listener);
|
|
|
|
|
|
|
|
kiosk_shell_surface_set_output(shsurf, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct kiosk_shell_surface *
|
|
|
|
kiosk_shell_surface_get_parent_root(struct kiosk_shell_surface *shsurf)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *root = shsurf;
|
|
|
|
while (root->parent)
|
|
|
|
root = root->parent;
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2023-08-03 15:52:02 +03:00
|
|
|
kiosk_shell_output_has_app_id(char *config_app_ids, const char *app_id);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
static struct weston_output *
|
2023-08-03 16:03:21 +03:00
|
|
|
kiosk_shell_surface_find_best_output_for_xwayland(struct kiosk_shell_surface *shsurf)
|
2020-04-21 18:23:37 +03:00
|
|
|
{
|
|
|
|
struct kiosk_shell_output *shoutput;
|
2023-08-03 16:03:21 +03:00
|
|
|
const char *wm_name;
|
|
|
|
const char *wm_class;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
2023-08-03 16:03:21 +03:00
|
|
|
wm_name = xwayland_get_xwayland_name(shsurf, WM_NAME);
|
|
|
|
wm_class = xwayland_get_xwayland_name(shsurf, WM_CLASS);
|
|
|
|
|
|
|
|
if (wm_name && wm_class) {
|
|
|
|
bool found_wm_name = false;
|
|
|
|
bool found_wm_class = false;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
wl_list_for_each(shoutput, &shsurf->shell->output_list, link) {
|
2023-08-03 16:03:21 +03:00
|
|
|
if (kiosk_shell_output_has_app_id(shoutput->x11_wm_name_app_ids,
|
|
|
|
wm_name))
|
|
|
|
found_wm_name = true;
|
|
|
|
|
|
|
|
if (kiosk_shell_output_has_app_id(shoutput->x11_wm_class_app_ids,
|
|
|
|
wm_class))
|
|
|
|
found_wm_class = true;
|
|
|
|
|
|
|
|
if (found_wm_name && found_wm_class) {
|
2023-08-03 15:52:02 +03:00
|
|
|
shsurf->appid_output_assigned = true;
|
|
|
|
return shoutput->output;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-03 16:03:21 +03:00
|
|
|
/* fallback to search for each entry */
|
|
|
|
if (wm_name) {
|
|
|
|
wl_list_for_each(shoutput, &shsurf->shell->output_list, link) {
|
|
|
|
if (kiosk_shell_output_has_app_id(shoutput->x11_wm_name_app_ids,
|
|
|
|
wm_name)) {
|
|
|
|
shsurf->appid_output_assigned = true;
|
|
|
|
return shoutput->output;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wm_class) {
|
2023-08-03 15:52:02 +03:00
|
|
|
wl_list_for_each(shoutput, &shsurf->shell->output_list, link) {
|
2023-08-03 16:03:21 +03:00
|
|
|
if (kiosk_shell_output_has_app_id(shoutput->x11_wm_class_app_ids,
|
|
|
|
wm_class)) {
|
2023-08-03 15:52:02 +03:00
|
|
|
shsurf->appid_output_assigned = true;
|
|
|
|
return shoutput->output;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-03 16:03:21 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct weston_output *
|
|
|
|
kiosk_shell_surface_find_best_output(struct kiosk_shell_surface *shsurf)
|
|
|
|
{
|
|
|
|
struct weston_output *output;
|
|
|
|
struct kiosk_shell_output *shoutput;
|
|
|
|
struct kiosk_shell_surface *root;
|
|
|
|
const char *app_id;
|
|
|
|
|
|
|
|
/* Always use current output if any. */
|
|
|
|
if (shsurf->output)
|
|
|
|
return shsurf->output;
|
|
|
|
|
|
|
|
/* Check if we have a designated output for this app. */
|
|
|
|
app_id = weston_desktop_surface_get_app_id(shsurf->desktop_surface);
|
2023-08-03 15:52:02 +03:00
|
|
|
if (app_id) {
|
|
|
|
wl_list_for_each(shoutput, &shsurf->shell->output_list, link) {
|
2023-08-03 16:03:21 +03:00
|
|
|
if (kiosk_shell_output_has_app_id(shoutput->app_ids, app_id)) {
|
2021-04-30 21:53:16 +03:00
|
|
|
shsurf->appid_output_assigned = true;
|
2020-04-21 18:23:37 +03:00
|
|
|
return shoutput->output;
|
2021-04-30 21:53:16 +03:00
|
|
|
}
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-03 16:03:21 +03:00
|
|
|
output = kiosk_shell_surface_find_best_output_for_xwayland(shsurf);
|
|
|
|
if (output)
|
|
|
|
return output;
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
/* Group all related windows in the same output. */
|
|
|
|
root = kiosk_shell_surface_get_parent_root(shsurf);
|
|
|
|
if (root->output)
|
|
|
|
return root->output;
|
|
|
|
|
2022-11-22 14:28:57 +03:00
|
|
|
output = weston_shell_utils_get_focused_output(shsurf->shell->compositor);
|
2020-04-21 18:23:37 +03:00
|
|
|
if (output)
|
|
|
|
return output;
|
|
|
|
|
2022-11-22 14:28:57 +03:00
|
|
|
output = weston_shell_utils_get_default_output(shsurf->shell->compositor);
|
2020-04-21 18:23:37 +03:00
|
|
|
if (output)
|
|
|
|
return output;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_surface_set_output(struct kiosk_shell_surface *shsurf,
|
|
|
|
struct weston_output *output)
|
|
|
|
{
|
|
|
|
shsurf->output = output;
|
|
|
|
|
|
|
|
if (shsurf->output_destroy_listener.notify) {
|
|
|
|
wl_list_remove(&shsurf->output_destroy_listener.link);
|
|
|
|
shsurf->output_destroy_listener.notify = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!shsurf->output)
|
|
|
|
return;
|
|
|
|
|
|
|
|
shsurf->output_destroy_listener.notify =
|
|
|
|
kiosk_shell_surface_notify_output_destroy;
|
|
|
|
wl_signal_add(&shsurf->output->destroy_signal,
|
|
|
|
&shsurf->output_destroy_listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_surface_set_fullscreen(struct kiosk_shell_surface *shsurf,
|
|
|
|
struct weston_output *output)
|
|
|
|
{
|
|
|
|
if (!output)
|
|
|
|
output = kiosk_shell_surface_find_best_output(shsurf);
|
|
|
|
|
|
|
|
kiosk_shell_surface_set_output(shsurf, output);
|
|
|
|
|
|
|
|
weston_desktop_surface_set_fullscreen(shsurf->desktop_surface, true);
|
|
|
|
if (shsurf->output)
|
|
|
|
weston_desktop_surface_set_size(shsurf->desktop_surface,
|
|
|
|
shsurf->output->width,
|
|
|
|
shsurf->output->height);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_surface_set_maximized(struct kiosk_shell_surface *shsurf)
|
|
|
|
{
|
|
|
|
struct weston_output *output =
|
|
|
|
kiosk_shell_surface_find_best_output(shsurf);
|
|
|
|
|
|
|
|
kiosk_shell_surface_set_output(shsurf, output);
|
|
|
|
|
|
|
|
weston_desktop_surface_set_maximized(shsurf->desktop_surface, true);
|
|
|
|
if (shsurf->output)
|
|
|
|
weston_desktop_surface_set_size(shsurf->desktop_surface,
|
|
|
|
shsurf->output->width,
|
|
|
|
shsurf->output->height);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_surface_set_normal(struct kiosk_shell_surface *shsurf)
|
|
|
|
{
|
|
|
|
if (!shsurf->output)
|
|
|
|
kiosk_shell_surface_set_output(shsurf,
|
|
|
|
kiosk_shell_surface_find_best_output(shsurf));
|
|
|
|
|
|
|
|
weston_desktop_surface_set_fullscreen(shsurf->desktop_surface, false);
|
|
|
|
weston_desktop_surface_set_maximized(shsurf->desktop_surface, false);
|
|
|
|
weston_desktop_surface_set_size(shsurf->desktop_surface, 0, 0);
|
|
|
|
}
|
|
|
|
|
2023-05-27 01:01:21 +03:00
|
|
|
static bool
|
|
|
|
kiosk_shell_surface_is_surface_in_tree(struct kiosk_shell_surface *shsurf,
|
|
|
|
struct kiosk_shell_surface *shroot)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *s;
|
|
|
|
|
|
|
|
wl_list_for_each(s, &shroot->surface_tree_list, surface_tree_link) {
|
|
|
|
if (s == shsurf)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
kiosk_shell_surface_is_descendant_of(struct kiosk_shell_surface *shsurf,
|
|
|
|
struct kiosk_shell_surface *ancestor)
|
|
|
|
{
|
|
|
|
while (shsurf) {
|
|
|
|
if (shsurf == ancestor)
|
|
|
|
return true;
|
|
|
|
shsurf = shsurf->parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
active_surface_tree_move_element_to_top(struct wl_list *active_surface_tree,
|
|
|
|
struct wl_list *element)
|
|
|
|
{
|
|
|
|
wl_list_remove(element);
|
|
|
|
wl_list_insert(active_surface_tree, element);
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
static void
|
|
|
|
kiosk_shell_surface_set_parent(struct kiosk_shell_surface *shsurf,
|
|
|
|
struct kiosk_shell_surface *parent)
|
|
|
|
{
|
2023-05-27 01:01:21 +03:00
|
|
|
struct kiosk_shell_output *shoutput =
|
|
|
|
kiosk_shell_find_shell_output(shsurf->shell,
|
|
|
|
shsurf->output);
|
|
|
|
struct kiosk_shell_surface *shroot = parent ?
|
|
|
|
kiosk_shell_surface_get_parent_root(parent) :
|
|
|
|
kiosk_shell_surface_get_parent_root(shsurf);
|
|
|
|
|
|
|
|
/* There are cases where xdg clients call .set_parent(nil) on a surface
|
|
|
|
* that does not have a parent. The protocol states that this is
|
|
|
|
* effectively a no-op. */
|
|
|
|
if (!parent && shsurf == shroot)
|
|
|
|
return;
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
if (shsurf->parent_destroy_listener.notify) {
|
|
|
|
wl_list_remove(&shsurf->parent_destroy_listener.link);
|
|
|
|
shsurf->parent_destroy_listener.notify = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
shsurf->parent = parent;
|
|
|
|
|
|
|
|
if (shsurf->parent) {
|
|
|
|
shsurf->parent_destroy_listener.notify =
|
|
|
|
kiosk_shell_surface_notify_parent_destroy;
|
2023-05-26 19:29:10 +03:00
|
|
|
wl_signal_add(&parent->parent_destroy_signal,
|
2020-04-21 18:23:37 +03:00
|
|
|
&shsurf->parent_destroy_listener);
|
2023-05-27 01:01:21 +03:00
|
|
|
|
|
|
|
if (!kiosk_shell_surface_is_surface_in_tree(shsurf, shroot)) {
|
|
|
|
active_surface_tree_move_element_to_top(&shroot->surface_tree_list,
|
|
|
|
&shsurf->surface_tree_link);
|
|
|
|
}
|
2020-04-21 18:23:37 +03:00
|
|
|
kiosk_shell_surface_set_output(shsurf, NULL);
|
|
|
|
kiosk_shell_surface_set_normal(shsurf);
|
|
|
|
} else {
|
2023-05-27 01:01:21 +03:00
|
|
|
struct kiosk_shell_surface *s, *tmp;
|
|
|
|
|
|
|
|
/* Relink the child and all its descendents to a new surface
|
|
|
|
* tree list, with the child as root. */
|
|
|
|
wl_list_init(&shsurf->surface_tree_list);
|
|
|
|
wl_list_for_each_reverse_safe(s, tmp, &shroot->surface_tree_list,
|
|
|
|
surface_tree_link) {
|
|
|
|
if (kiosk_shell_surface_is_descendant_of(s, shsurf)) {
|
|
|
|
active_surface_tree_move_element_to_top(&shsurf->surface_tree_list,
|
|
|
|
&s->surface_tree_link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kiosk_shell_output_set_active_surface_tree(shoutput, shsurf);
|
2020-04-21 18:23:37 +03:00
|
|
|
kiosk_shell_surface_set_fullscreen(shsurf, shsurf->output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_surface_reconfigure_for_output(struct kiosk_shell_surface *shsurf)
|
|
|
|
{
|
|
|
|
struct weston_desktop_surface *desktop_surface;
|
|
|
|
|
|
|
|
if (!shsurf->output)
|
|
|
|
return;
|
|
|
|
|
|
|
|
desktop_surface = shsurf->desktop_surface;
|
|
|
|
|
|
|
|
if (weston_desktop_surface_get_maximized(desktop_surface) ||
|
|
|
|
weston_desktop_surface_get_fullscreen(desktop_surface)) {
|
|
|
|
weston_desktop_surface_set_size(desktop_surface,
|
|
|
|
shsurf->output->width,
|
|
|
|
shsurf->output->height);
|
|
|
|
}
|
|
|
|
|
2022-11-22 14:28:57 +03:00
|
|
|
weston_shell_utils_center_on_output(shsurf->view, shsurf->output);
|
2020-04-21 18:23:37 +03:00
|
|
|
weston_view_update_transform(shsurf->view);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_surface_destroy(struct kiosk_shell_surface *shsurf)
|
|
|
|
{
|
|
|
|
wl_signal_emit(&shsurf->destroy_signal, shsurf);
|
kiosk-shell: Introduce surface tree lists to the kiosk shell
The following patchset implements proper z-order for xdg surfaces in the kiosk
shell. For this it introduces to the kiosk shell the concept of a "surface
tree": a list of kiosk shell surface structures having a common ancestor (in
the xdg protocol sense).
The design is based on the following assumptions that the kiosk shell currently
makes:
- A kiosk surface with no parent must be fullscreen.
- If a parent is set on a kiosk surface, that surface is assigned the output of
the root kiosk surface. This means that all kiosk surfaces in a surface tree
will always have the same output.
- There is no possibility to minimize a kiosk surface.
With these in mind, the following design decisions were deemed convenient:
- For every output, at most one surface tree list will be active. This means
that, for a given output, only views belonging to surfaces of the same
surface tree will be in the normal layer. Moreover, all such views will be in
the normal layer if the surface tree list is active.
- The z-order of surface trees (the weston views' relative placement in the
normal layer) is determined by the placement of their corresponding kiosk
surface in the surface tree list.
Each kiosk shell surface begins its life as root of its own surface tree list.
Whenever a parent is set on a surface, that surface is linked to the surface
tree list of the root surface of the parent. If a parent kiosk shell surface is
destroyed, its children will keep the link to the root surface's surface tree
list. If the destroyed parent is also the root surface of the surface tree,
each child is unlinked from this root and they become the root of a new surface
tree.
This commit introduces to the kiosk_shell_surface structure the fields
'surface_tree_list', representing the surface tree list to which the surface is
linked at creation as its root, and 'surface_tree_link', the link to the
surface tree list.
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-05-26 02:54:03 +03:00
|
|
|
wl_list_remove(&shsurf->surface_tree_link);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
weston_desktop_surface_set_user_data(shsurf->desktop_surface, NULL);
|
|
|
|
shsurf->desktop_surface = NULL;
|
|
|
|
|
|
|
|
weston_desktop_surface_unlink_view(shsurf->view);
|
|
|
|
|
|
|
|
weston_view_destroy(shsurf->view);
|
|
|
|
|
|
|
|
if (shsurf->output_destroy_listener.notify) {
|
|
|
|
wl_list_remove(&shsurf->output_destroy_listener.link);
|
|
|
|
shsurf->output_destroy_listener.notify = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shsurf->parent_destroy_listener.notify) {
|
|
|
|
wl_list_remove(&shsurf->parent_destroy_listener.link);
|
|
|
|
shsurf->parent_destroy_listener.notify = NULL;
|
|
|
|
shsurf->parent = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(shsurf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct kiosk_shell_surface *
|
|
|
|
kiosk_shell_surface_create(struct kiosk_shell *shell,
|
|
|
|
struct weston_desktop_surface *desktop_surface)
|
|
|
|
{
|
|
|
|
struct weston_desktop_client *client =
|
|
|
|
weston_desktop_surface_get_client(desktop_surface);
|
|
|
|
struct wl_client *wl_client =
|
|
|
|
weston_desktop_client_get_client(client);
|
|
|
|
struct weston_view *view;
|
|
|
|
struct kiosk_shell_surface *shsurf;
|
|
|
|
|
|
|
|
view = weston_desktop_surface_create_view(desktop_surface);
|
|
|
|
if (!view)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
shsurf = zalloc(sizeof *shsurf);
|
|
|
|
if (!shsurf) {
|
|
|
|
if (wl_client)
|
|
|
|
wl_client_post_no_memory(wl_client);
|
|
|
|
else
|
|
|
|
weston_log("no memory to allocate shell surface\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
shsurf->desktop_surface = desktop_surface;
|
|
|
|
shsurf->view = view;
|
|
|
|
shsurf->shell = shell;
|
2021-04-30 21:53:16 +03:00
|
|
|
shsurf->appid_output_assigned = false;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
weston_desktop_surface_set_user_data(desktop_surface, shsurf);
|
|
|
|
|
|
|
|
wl_signal_init(&shsurf->destroy_signal);
|
2023-05-26 19:29:10 +03:00
|
|
|
wl_signal_init(&shsurf->parent_destroy_signal);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
kiosk-shell: Introduce surface tree lists to the kiosk shell
The following patchset implements proper z-order for xdg surfaces in the kiosk
shell. For this it introduces to the kiosk shell the concept of a "surface
tree": a list of kiosk shell surface structures having a common ancestor (in
the xdg protocol sense).
The design is based on the following assumptions that the kiosk shell currently
makes:
- A kiosk surface with no parent must be fullscreen.
- If a parent is set on a kiosk surface, that surface is assigned the output of
the root kiosk surface. This means that all kiosk surfaces in a surface tree
will always have the same output.
- There is no possibility to minimize a kiosk surface.
With these in mind, the following design decisions were deemed convenient:
- For every output, at most one surface tree list will be active. This means
that, for a given output, only views belonging to surfaces of the same
surface tree will be in the normal layer. Moreover, all such views will be in
the normal layer if the surface tree list is active.
- The z-order of surface trees (the weston views' relative placement in the
normal layer) is determined by the placement of their corresponding kiosk
surface in the surface tree list.
Each kiosk shell surface begins its life as root of its own surface tree list.
Whenever a parent is set on a surface, that surface is linked to the surface
tree list of the root surface of the parent. If a parent kiosk shell surface is
destroyed, its children will keep the link to the root surface's surface tree
list. If the destroyed parent is also the root surface of the surface tree,
each child is unlinked from this root and they become the root of a new surface
tree.
This commit introduces to the kiosk_shell_surface structure the fields
'surface_tree_list', representing the surface tree list to which the surface is
linked at creation as its root, and 'surface_tree_link', the link to the
surface tree list.
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-05-26 02:54:03 +03:00
|
|
|
/* start life inserting itself as root of its own surface tree list */
|
|
|
|
wl_list_init(&shsurf->surface_tree_list);
|
|
|
|
wl_list_init(&shsurf->surface_tree_link);
|
|
|
|
wl_list_insert(&shsurf->surface_tree_list, &shsurf->surface_tree_link);
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
return shsurf;
|
|
|
|
}
|
|
|
|
|
2021-03-05 22:58:40 +03:00
|
|
|
static void
|
|
|
|
kiosk_shell_surface_activate(struct kiosk_shell_surface *shsurf,
|
|
|
|
struct kiosk_shell_seat *kiosk_seat,
|
|
|
|
uint32_t activate_flags)
|
|
|
|
{
|
|
|
|
struct weston_desktop_surface *dsurface = shsurf->desktop_surface;
|
|
|
|
struct weston_surface *surface =
|
|
|
|
weston_desktop_surface_get_surface(dsurface);
|
2023-06-06 02:30:35 +03:00
|
|
|
struct kiosk_shell_output *shoutput =
|
|
|
|
kiosk_shell_find_shell_output(shsurf->shell, shsurf->output);
|
2021-03-05 22:58:40 +03:00
|
|
|
|
|
|
|
/* keyboard focus */
|
|
|
|
weston_view_activate_input(shsurf->view, kiosk_seat->seat, activate_flags);
|
|
|
|
|
|
|
|
/* xdg-shell deactivation if there's a focused one */
|
|
|
|
if (kiosk_seat->focused_surface) {
|
|
|
|
struct kiosk_shell_surface *current_focus =
|
|
|
|
get_kiosk_shell_surface(kiosk_seat->focused_surface);
|
|
|
|
struct weston_desktop_surface *dsurface_focus;
|
|
|
|
assert(current_focus);
|
|
|
|
|
|
|
|
dsurface_focus = current_focus->desktop_surface;
|
|
|
|
if (--current_focus->focus_count == 0)
|
|
|
|
weston_desktop_surface_set_activated(dsurface_focus, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* xdg-shell activation for the new one */
|
|
|
|
kiosk_seat->focused_surface = surface;
|
|
|
|
if (shsurf->focus_count++ == 0)
|
|
|
|
weston_desktop_surface_set_activated(dsurface, true);
|
2021-11-09 20:25:46 +03:00
|
|
|
|
2023-06-06 02:30:35 +03:00
|
|
|
/* raise the focused subtree to the top of the visible layer */
|
|
|
|
kiosk_shell_output_raise_surface_subtree(shoutput, shsurf);
|
2021-03-05 22:58:40 +03:00
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
/*
|
|
|
|
* kiosk_shell_seat
|
|
|
|
*/
|
|
|
|
|
2020-10-24 16:26:59 +03:00
|
|
|
static void
|
|
|
|
kiosk_shell_seat_destroy(struct kiosk_shell_seat *shseat)
|
|
|
|
{
|
|
|
|
wl_list_remove(&shseat->seat_destroy_listener.link);
|
|
|
|
wl_list_remove(&shseat->link);
|
|
|
|
free(shseat);
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
static void
|
|
|
|
kiosk_shell_seat_handle_destroy(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_seat *shseat =
|
|
|
|
container_of(listener,
|
|
|
|
struct kiosk_shell_seat, seat_destroy_listener);
|
|
|
|
|
2020-10-24 16:26:59 +03:00
|
|
|
kiosk_shell_seat_destroy(shseat);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct kiosk_shell_seat *
|
2020-10-24 16:26:59 +03:00
|
|
|
kiosk_shell_seat_create(struct kiosk_shell *shell, struct weston_seat *seat)
|
2020-04-21 18:23:37 +03:00
|
|
|
{
|
|
|
|
struct kiosk_shell_seat *shseat;
|
|
|
|
|
2021-11-02 14:41:30 +03:00
|
|
|
if (wl_list_length(&shell->seat_list) > 0) {
|
|
|
|
weston_log("WARNING: multiple seats detected. kiosk-shell "
|
|
|
|
"can not handle multiple seats!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
shseat = zalloc(sizeof *shseat);
|
|
|
|
if (!shseat) {
|
|
|
|
weston_log("no memory to allocate shell seat\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
shseat->seat = seat;
|
|
|
|
|
|
|
|
shseat->seat_destroy_listener.notify = kiosk_shell_seat_handle_destroy;
|
|
|
|
wl_signal_add(&seat->destroy_signal, &shseat->seat_destroy_listener);
|
|
|
|
|
2020-10-24 16:26:59 +03:00
|
|
|
wl_list_insert(&shell->seat_list, &shseat->link);
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
return shseat;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* kiosk_shell_output
|
|
|
|
*/
|
|
|
|
|
2023-05-27 01:00:41 +03:00
|
|
|
static void
|
|
|
|
kiosk_shell_output_set_active_surface_tree(struct kiosk_shell_output *shoutput,
|
|
|
|
struct kiosk_shell_surface *shroot)
|
|
|
|
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell = shoutput->shell;
|
|
|
|
struct kiosk_shell_surface *s;
|
|
|
|
|
|
|
|
/* Remove the previous active surface tree (i.e., move the tree to
|
|
|
|
* WESTON_LAYER_POSITION_HIDDEN) */
|
|
|
|
if (shoutput->active_surface_tree) {
|
|
|
|
wl_list_for_each_reverse(s, shoutput->active_surface_tree, surface_tree_link) {
|
|
|
|
weston_view_move_to_layer(s->view,
|
|
|
|
&shell->inactive_layer.view_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shroot) {
|
|
|
|
wl_list_for_each_reverse(s, &shroot->surface_tree_list, surface_tree_link) {
|
|
|
|
weston_view_move_to_layer(s->view,
|
|
|
|
&shell->normal_layer.view_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
shoutput->active_surface_tree = shroot ?
|
|
|
|
&shroot->surface_tree_list :
|
|
|
|
NULL;
|
|
|
|
}
|
|
|
|
|
2023-06-06 02:30:35 +03:00
|
|
|
/* Raises the subtree originating at the specified 'shroot' of the output's
|
|
|
|
* active surface tree to the top of the visible layer. */
|
|
|
|
static void
|
|
|
|
kiosk_shell_output_raise_surface_subtree(struct kiosk_shell_output *shoutput,
|
|
|
|
struct kiosk_shell_surface *shroot)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell = shroot->shell;
|
|
|
|
struct wl_list tmp_list;
|
|
|
|
struct kiosk_shell_surface *s, *tmp_s;
|
|
|
|
|
|
|
|
wl_list_init(&tmp_list);
|
|
|
|
|
2023-08-08 12:29:56 +03:00
|
|
|
if (!shoutput->active_surface_tree)
|
|
|
|
return;
|
|
|
|
|
2023-06-06 02:30:35 +03:00
|
|
|
/* Move all shell surfaces in the active surface tree starting at
|
|
|
|
* shroot to the tmp_list while maintaining the relative order. */
|
|
|
|
wl_list_for_each_reverse_safe(s, tmp_s,
|
|
|
|
shoutput->active_surface_tree, surface_tree_link) {
|
|
|
|
if (kiosk_shell_surface_is_descendant_of(s, shroot)) {
|
|
|
|
active_surface_tree_move_element_to_top(&tmp_list,
|
|
|
|
&s->surface_tree_link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now insert the views corresponding to the shell surfaces stored to
|
|
|
|
* the top of the layer in the proper order.
|
|
|
|
* Also remove the shell surface from tmp_list and insert it at the top
|
|
|
|
* of the output's active surface tree. */
|
|
|
|
wl_list_for_each_reverse_safe(s, tmp_s, &tmp_list, surface_tree_link) {
|
|
|
|
weston_view_move_to_layer(s->view, &shell->normal_layer.view_list);
|
|
|
|
|
|
|
|
active_surface_tree_move_element_to_top(shoutput->active_surface_tree,
|
|
|
|
&s->surface_tree_link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
static int
|
|
|
|
kiosk_shell_background_surface_get_label(struct weston_surface *surface,
|
|
|
|
char *buf, size_t len)
|
|
|
|
{
|
|
|
|
return snprintf(buf, len, "kiosk shell background surface");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_output_recreate_background(struct kiosk_shell_output *shoutput)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell = shoutput->shell;
|
2022-01-17 16:54:21 +03:00
|
|
|
struct weston_compositor *ec = shell->compositor;
|
2020-04-21 18:23:37 +03:00
|
|
|
struct weston_output *output = shoutput->output;
|
2021-03-26 16:55:05 +03:00
|
|
|
struct weston_config_section *shell_section = NULL;
|
|
|
|
uint32_t bg_color = 0x0;
|
2022-01-17 16:58:16 +03:00
|
|
|
struct weston_curtain_params curtain_params = {};
|
2020-04-21 18:23:37 +03:00
|
|
|
|
2022-01-17 17:24:03 +03:00
|
|
|
if (shoutput->curtain)
|
2022-11-22 14:28:57 +03:00
|
|
|
weston_shell_utils_curtain_destroy(shoutput->curtain);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
if (!output)
|
|
|
|
return;
|
|
|
|
|
2021-03-26 16:55:05 +03:00
|
|
|
if (shell->config)
|
|
|
|
shell_section = weston_config_get_section(shell->config, "shell", NULL, NULL);
|
|
|
|
if (shell_section)
|
|
|
|
weston_config_section_get_color(shell_section, "background-color",
|
|
|
|
&bg_color, 0x00000000);
|
|
|
|
|
2022-01-17 16:58:16 +03:00
|
|
|
curtain_params.r = ((bg_color >> 16) & 0xff) / 255.0;
|
|
|
|
curtain_params.g = ((bg_color >> 8) & 0xff) / 255.0;
|
|
|
|
curtain_params.b = ((bg_color >> 0) & 0xff) / 255.0;
|
2022-01-18 21:17:17 +03:00
|
|
|
curtain_params.a = 1.0;
|
2021-03-08 23:45:52 +03:00
|
|
|
|
2022-09-06 15:50:53 +03:00
|
|
|
curtain_params.pos = output->pos;
|
2022-01-17 17:05:06 +03:00
|
|
|
curtain_params.width = output->width;
|
|
|
|
curtain_params.height = output->height;
|
|
|
|
|
2022-01-18 21:59:33 +03:00
|
|
|
curtain_params.capture_input = true;
|
|
|
|
|
2022-01-17 16:58:16 +03:00
|
|
|
curtain_params.get_label = kiosk_shell_background_surface_get_label;
|
|
|
|
curtain_params.surface_committed = NULL;
|
|
|
|
curtain_params.surface_private = NULL;
|
2021-03-26 16:55:05 +03:00
|
|
|
|
2022-11-22 14:28:57 +03:00
|
|
|
shoutput->curtain = weston_shell_utils_curtain_create(ec, &curtain_params);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
2022-01-17 17:24:03 +03:00
|
|
|
weston_surface_set_role(shoutput->curtain->view->surface,
|
2020-04-21 18:23:37 +03:00
|
|
|
"kiosk-shell-background", NULL, 0);
|
|
|
|
|
2022-01-17 17:24:03 +03:00
|
|
|
shoutput->curtain->view->surface->output = output;
|
2023-06-19 22:51:59 +03:00
|
|
|
|
|
|
|
weston_view_move_to_layer(shoutput->curtain->view,
|
|
|
|
&shell->background_layer.view_list);
|
2022-01-17 17:24:03 +03:00
|
|
|
weston_view_set_output(shoutput->curtain->view, output);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_output_destroy(struct kiosk_shell_output *shoutput)
|
|
|
|
{
|
|
|
|
shoutput->output = NULL;
|
|
|
|
shoutput->output_destroy_listener.notify = NULL;
|
|
|
|
|
2022-01-17 17:24:03 +03:00
|
|
|
if (shoutput->curtain)
|
2022-11-22 14:28:57 +03:00
|
|
|
weston_shell_utils_curtain_destroy(shoutput->curtain);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
wl_list_remove(&shoutput->output_destroy_listener.link);
|
|
|
|
wl_list_remove(&shoutput->link);
|
|
|
|
|
|
|
|
free(shoutput->app_ids);
|
2023-08-03 15:52:02 +03:00
|
|
|
free(shoutput->x11_wm_name_app_ids);
|
|
|
|
free(shoutput->x11_wm_class_app_ids);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
free(shoutput);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2023-08-03 15:52:02 +03:00
|
|
|
kiosk_shell_output_has_app_id(char *config_app_ids, const char *app_id)
|
2020-04-21 18:23:37 +03:00
|
|
|
{
|
|
|
|
char *cur;
|
|
|
|
size_t app_id_len;
|
|
|
|
|
2023-08-03 15:52:02 +03:00
|
|
|
if (!config_app_ids)
|
2020-04-21 18:23:37 +03:00
|
|
|
return false;
|
|
|
|
|
2023-08-03 15:52:02 +03:00
|
|
|
cur = config_app_ids;
|
2020-04-21 18:23:37 +03:00
|
|
|
app_id_len = strlen(app_id);
|
|
|
|
|
|
|
|
while ((cur = strstr(cur, app_id))) {
|
|
|
|
/* Check whether we have found a complete match of app_id. */
|
|
|
|
if ((cur[app_id_len] == ',' || cur[app_id_len] == '\0') &&
|
2023-08-03 15:52:02 +03:00
|
|
|
(cur == config_app_ids || cur[-1] == ','))
|
2020-04-21 18:23:37 +03:00
|
|
|
return true;
|
|
|
|
cur++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_output_configure(struct kiosk_shell_output *shoutput)
|
|
|
|
{
|
|
|
|
struct weston_config *wc = wet_get_config(shoutput->shell->compositor);
|
|
|
|
struct weston_config_section *section =
|
|
|
|
weston_config_get_section(wc, "output", "name", shoutput->output->name);
|
|
|
|
|
|
|
|
assert(shoutput->app_ids == NULL);
|
2023-08-03 15:52:02 +03:00
|
|
|
assert(shoutput->x11_wm_name_app_ids == NULL);
|
|
|
|
assert(shoutput->x11_wm_class_app_ids == NULL);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
if (section) {
|
|
|
|
weston_config_section_get_string(section, "app-ids",
|
|
|
|
&shoutput->app_ids, NULL);
|
2023-08-03 15:52:02 +03:00
|
|
|
weston_config_section_get_string(section, "x11-wm-name",
|
|
|
|
&shoutput->x11_wm_name_app_ids, NULL);
|
|
|
|
weston_config_section_get_string(section, "x11-wm-class",
|
|
|
|
&shoutput->x11_wm_class_app_ids, NULL);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_output_notify_output_destroy(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_output *shoutput =
|
|
|
|
container_of(listener,
|
|
|
|
struct kiosk_shell_output, output_destroy_listener);
|
|
|
|
|
|
|
|
kiosk_shell_output_destroy(shoutput);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct kiosk_shell_output *
|
|
|
|
kiosk_shell_output_create(struct kiosk_shell *shell, struct weston_output *output)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_output *shoutput;
|
|
|
|
|
|
|
|
shoutput = zalloc(sizeof *shoutput);
|
|
|
|
if (shoutput == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
shoutput->output = output;
|
|
|
|
shoutput->shell = shell;
|
|
|
|
|
|
|
|
shoutput->output_destroy_listener.notify =
|
|
|
|
kiosk_shell_output_notify_output_destroy;
|
|
|
|
wl_signal_add(&shoutput->output->destroy_signal,
|
|
|
|
&shoutput->output_destroy_listener);
|
|
|
|
|
|
|
|
wl_list_insert(shell->output_list.prev, &shoutput->link);
|
|
|
|
|
|
|
|
kiosk_shell_output_recreate_background(shoutput);
|
|
|
|
kiosk_shell_output_configure(shoutput);
|
|
|
|
|
|
|
|
return shoutput;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* libweston-desktop
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_added(struct weston_desktop_surface *desktop_surface,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell = data;
|
|
|
|
struct kiosk_shell_surface *shsurf;
|
2021-10-21 14:09:01 +03:00
|
|
|
struct weston_surface *surface =
|
|
|
|
weston_desktop_surface_get_surface(desktop_surface);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
shsurf = kiosk_shell_surface_create(shell, desktop_surface);
|
|
|
|
if (!shsurf)
|
|
|
|
return;
|
|
|
|
|
2022-11-22 14:28:57 +03:00
|
|
|
weston_surface_set_label_func(surface, weston_shell_utils_surface_get_label);
|
2020-04-21 18:23:37 +03:00
|
|
|
kiosk_shell_surface_set_fullscreen(shsurf, NULL);
|
|
|
|
}
|
|
|
|
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
/* Return the shell surface that should gain focus after the specified shsurf is
|
2020-04-21 18:23:37 +03:00
|
|
|
* destroyed. We prefer the top remaining view from the same parent surface,
|
|
|
|
* but if we can't find one we fall back to the top view regardless of
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
* parentage.
|
|
|
|
* First look for the successor in the normal layer, and if that
|
|
|
|
* fails, look for it in the inactive layer, and if that also fails, then there
|
|
|
|
* is no successor. */
|
|
|
|
static struct kiosk_shell_surface *
|
|
|
|
find_focus_successor(struct kiosk_shell_surface *shsurf,
|
2021-03-05 22:58:40 +03:00
|
|
|
struct weston_surface *focused_surface)
|
2020-04-21 18:23:37 +03:00
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *parent_root =
|
|
|
|
kiosk_shell_surface_get_parent_root(shsurf);
|
|
|
|
struct weston_view *top_view = NULL;
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
struct kiosk_shell_surface *successor = NULL;
|
|
|
|
struct wl_list *layers = &shsurf->shell->compositor->layer_list;
|
|
|
|
struct weston_layer *layer;
|
2020-04-21 18:23:37 +03:00
|
|
|
struct weston_view *view;
|
|
|
|
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
wl_list_for_each(layer, layers, link) {
|
|
|
|
struct kiosk_shell *shell = shsurf->shell;
|
2021-12-22 17:52:12 +03:00
|
|
|
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
if (layer != &shell->inactive_layer &&
|
|
|
|
layer != &shell->normal_layer) {
|
2020-04-21 18:23:37 +03:00
|
|
|
continue;
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
}
|
|
|
|
wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
|
|
|
|
struct kiosk_shell_surface *view_shsurf;
|
|
|
|
struct kiosk_shell_surface *root;
|
2021-12-22 17:52:12 +03:00
|
|
|
|
2023-07-11 18:48:11 +03:00
|
|
|
if (view == shsurf->view)
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
continue;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
/* pick views only on the same output */
|
|
|
|
if (view->output != shsurf->output)
|
|
|
|
continue;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
view_shsurf = get_kiosk_shell_surface(view->surface);
|
|
|
|
if (!view_shsurf)
|
|
|
|
continue;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
if (!top_view)
|
|
|
|
top_view = view;
|
|
|
|
|
|
|
|
root = kiosk_shell_surface_get_parent_root(view_shsurf);
|
|
|
|
if (root == parent_root) {
|
|
|
|
top_view = view;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
if (top_view)
|
|
|
|
successor = get_kiosk_shell_surface(top_view->surface);
|
|
|
|
|
|
|
|
return successor;
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell = data;
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
weston_desktop_surface_get_user_data(desktop_surface);
|
|
|
|
struct weston_surface *surface =
|
|
|
|
weston_desktop_surface_get_surface(desktop_surface);
|
|
|
|
struct weston_seat *seat;
|
2021-03-05 22:58:40 +03:00
|
|
|
struct kiosk_shell_seat* kiosk_seat;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
if (!shsurf)
|
|
|
|
return;
|
|
|
|
|
2021-03-05 22:58:40 +03:00
|
|
|
seat = get_kiosk_shell_first_seat(shell);
|
|
|
|
kiosk_seat = get_kiosk_shell_seat(seat);
|
|
|
|
|
2023-05-26 19:29:10 +03:00
|
|
|
/* Inform children about destruction of their parent, so that we can
|
|
|
|
* reparent them and potentially relink surface tree links before
|
|
|
|
* finding a focus successor and activating a new surface. */
|
|
|
|
wl_signal_emit(&shsurf->parent_destroy_signal, shsurf);
|
|
|
|
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
/* We need to take into account that the surface being destroyed it not
|
|
|
|
* always the same as the focused surface, which could result in picking
|
|
|
|
* and *activating* the wrong window.
|
|
|
|
*
|
|
|
|
* Apply that only on the same output to avoid incorrectly picking an
|
|
|
|
* invalid surface, which could happen if the view being destroyed
|
|
|
|
* is on a output different than the focused_surface output */
|
2023-08-08 12:37:29 +03:00
|
|
|
if (seat && kiosk_seat && kiosk_seat->focused_surface &&
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
(kiosk_seat->focused_surface == surface ||
|
|
|
|
surface->output != kiosk_seat->focused_surface->output)) {
|
|
|
|
struct kiosk_shell_surface *successor;
|
2023-07-25 03:05:50 +03:00
|
|
|
struct kiosk_shell_output *shoutput;
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
|
|
|
|
successor = find_focus_successor(shsurf,
|
|
|
|
kiosk_seat->focused_surface);
|
2023-07-25 03:05:50 +03:00
|
|
|
shoutput = kiosk_shell_find_shell_output(shsurf->shell, shsurf->output);
|
|
|
|
if (shoutput && successor) {
|
|
|
|
enum weston_layer_position succesor_view_layer_pos;
|
|
|
|
|
|
|
|
succesor_view_layer_pos = weston_shell_utils_view_get_layer_position(successor->view);
|
|
|
|
if (succesor_view_layer_pos == WESTON_LAYER_POSITION_HIDDEN) {
|
|
|
|
struct kiosk_shell_surface *shroot =
|
|
|
|
kiosk_shell_surface_get_parent_root(successor);
|
|
|
|
|
|
|
|
kiosk_shell_output_set_active_surface_tree(shoutput,
|
|
|
|
shroot);
|
|
|
|
}
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
kiosk_shell_surface_activate(successor, kiosk_seat,
|
2021-03-05 22:58:40 +03:00
|
|
|
WESTON_ACTIVATE_FLAG_NONE);
|
|
|
|
} else {
|
kiosk-shell: Redesign the function 'find_focus_successor()'
The function find_focus_successor() is called when destroying a surface to find
a successor to the current focus. It, however, has the following issues:
- Its first parameter is the weston layer from which to search for a successor.
This is an unnecessary flexibility for our use, which only adds complexity to
the user of the function by having to make a call for each layer. We know
that we want to search for a successor first in the normal layer, and if that
fails, then in the inactive layer. So we change the signature of
find_focus_successor(), removing this first parameter.
- It includes logic to decide whether to do the search or not: if the destroyed
surface is different from the surface that currently has focus, and if their
outputs are the same, then abort and don't do the search. This returns NULL to
the calling function. The problem is that the function also returns NULL if
it does the search and finds no successor. The distinction for the failing
reason is lost, and the user of the function needs to add more logic to know
the reason for failure. To simplify, we take the logic out of
find_focus_successor() and inside the caller.
- It returns the successor view, although it receives surfaces and the client
has logic to retrieve the surface corresponding to the returned view. To
simplify and maintain symmetry, we change the signature so that the function
returns the surface corresponding to the successor view.
Fixes: #738
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
2023-07-20 05:46:20 +03:00
|
|
|
kiosk_seat->focused_surface = NULL;
|
2024-07-02 15:27:26 +03:00
|
|
|
if (shoutput)
|
|
|
|
kiosk_shell_output_set_active_surface_tree(shoutput,
|
|
|
|
NULL);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
kiosk_shell_surface_destroy(shsurf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
|
2022-02-08 20:58:10 +03:00
|
|
|
struct weston_coord_surface buf_offset, void *data)
|
2020-04-21 18:23:37 +03:00
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
weston_desktop_surface_get_user_data(desktop_surface);
|
|
|
|
struct weston_surface *surface =
|
|
|
|
weston_desktop_surface_get_surface(desktop_surface);
|
2021-04-30 21:53:16 +03:00
|
|
|
const char *app_id =
|
|
|
|
weston_desktop_surface_get_app_id(desktop_surface);
|
2020-04-21 18:23:37 +03:00
|
|
|
bool is_resized;
|
|
|
|
bool is_fullscreen;
|
|
|
|
|
2021-03-05 22:58:40 +03:00
|
|
|
assert(shsurf);
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
if (surface->width == 0)
|
|
|
|
return;
|
|
|
|
|
2021-04-30 21:53:16 +03:00
|
|
|
if (!shsurf->appid_output_assigned && app_id) {
|
|
|
|
struct weston_output *output = NULL;
|
|
|
|
|
|
|
|
/* reset previous output being set in _added() as the output is
|
|
|
|
* being cached */
|
|
|
|
shsurf->output = NULL;
|
|
|
|
output = kiosk_shell_surface_find_best_output(shsurf);
|
|
|
|
|
|
|
|
kiosk_shell_surface_set_output(shsurf, output);
|
|
|
|
weston_desktop_surface_set_size(shsurf->desktop_surface,
|
|
|
|
shsurf->output->width,
|
|
|
|
shsurf->output->height);
|
|
|
|
/* even if we couldn't find an appid set for a particular
|
|
|
|
* output still flag the shsurf as to a avoid changing the
|
|
|
|
* output every time */
|
|
|
|
shsurf->appid_output_assigned = true;
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
/* TODO: When the top-level surface is committed with a new size after an
|
|
|
|
* output resize, sometimes the view appears scaled. What state are we not
|
|
|
|
* updating?
|
|
|
|
*/
|
|
|
|
|
|
|
|
is_resized = surface->width != shsurf->last_width ||
|
|
|
|
surface->height != shsurf->last_height;
|
|
|
|
is_fullscreen = weston_desktop_surface_get_maximized(desktop_surface) ||
|
|
|
|
weston_desktop_surface_get_fullscreen(desktop_surface);
|
|
|
|
|
|
|
|
if (!weston_surface_is_mapped(surface) || (is_resized && is_fullscreen)) {
|
|
|
|
if (is_fullscreen || !shsurf->xwayland.is_set) {
|
2022-11-22 14:28:57 +03:00
|
|
|
weston_shell_utils_center_on_output(shsurf->view,
|
|
|
|
shsurf->output);
|
2020-04-21 18:23:37 +03:00
|
|
|
} else {
|
2022-02-08 19:43:05 +03:00
|
|
|
struct weston_coord_surface offset;
|
2020-04-21 18:23:37 +03:00
|
|
|
struct weston_geometry geometry =
|
|
|
|
weston_desktop_surface_get_geometry(desktop_surface);
|
|
|
|
|
2022-02-08 19:43:05 +03:00
|
|
|
offset = weston_coord_surface(-geometry.x, -geometry.y,
|
|
|
|
shsurf->view->surface);
|
|
|
|
weston_view_set_position_with_offset(shsurf->view,
|
|
|
|
shsurf->xwayland.pos,
|
|
|
|
offset);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
weston_view_update_transform(shsurf->view);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!weston_surface_is_mapped(surface)) {
|
2021-03-05 22:58:40 +03:00
|
|
|
struct weston_seat *seat =
|
|
|
|
get_kiosk_shell_first_seat(shsurf->shell);
|
2023-05-27 01:00:41 +03:00
|
|
|
struct kiosk_shell_output *shoutput =
|
|
|
|
kiosk_shell_find_shell_output(shsurf->shell,
|
|
|
|
shsurf->output);
|
2021-03-05 22:58:40 +03:00
|
|
|
struct kiosk_shell_seat *kiosk_seat;
|
2021-02-28 00:41:39 +03:00
|
|
|
|
2022-06-12 22:51:45 +03:00
|
|
|
weston_surface_map(surface);
|
2021-02-28 00:41:39 +03:00
|
|
|
|
2021-03-05 22:58:40 +03:00
|
|
|
kiosk_seat = get_kiosk_shell_seat(seat);
|
2023-05-27 01:00:41 +03:00
|
|
|
|
|
|
|
/* We are mapping a new surface tree root; set it active,
|
|
|
|
* replacing the previous one */
|
|
|
|
if (!shsurf->parent) {
|
|
|
|
kiosk_shell_output_set_active_surface_tree(shoutput,
|
|
|
|
shsurf);
|
|
|
|
}
|
|
|
|
|
2021-03-05 22:58:40 +03:00
|
|
|
if (seat && kiosk_seat)
|
|
|
|
kiosk_shell_surface_activate(shsurf, kiosk_seat,
|
|
|
|
WESTON_ACTIVATE_FLAG_NONE);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
|
2022-02-08 20:58:10 +03:00
|
|
|
if (!is_fullscreen && (buf_offset.c.x != 0 || buf_offset.c.y != 0)) {
|
|
|
|
struct weston_coord_global pos;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
2022-02-08 20:58:10 +03:00
|
|
|
pos = weston_view_get_pos_offset_global(shsurf->view);
|
|
|
|
weston_view_set_position_with_offset(shsurf->view,
|
|
|
|
pos, buf_offset);
|
2020-04-21 18:23:37 +03:00
|
|
|
weston_view_update_transform(shsurf->view);
|
|
|
|
}
|
|
|
|
|
|
|
|
shsurf->last_width = surface->width;
|
|
|
|
shsurf->last_height = surface->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_move(struct weston_desktop_surface *desktop_surface,
|
|
|
|
struct weston_seat *seat, uint32_t serial, void *shell)
|
|
|
|
{
|
|
|
|
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
|
|
|
|
struct weston_touch *touch = weston_seat_get_touch(seat);
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
weston_desktop_surface_get_user_data(desktop_surface);
|
|
|
|
struct weston_surface *surface =
|
|
|
|
weston_desktop_surface_get_surface(shsurf->desktop_surface);
|
|
|
|
struct weston_surface *focus;
|
|
|
|
|
|
|
|
if (pointer &&
|
|
|
|
pointer->focus &&
|
|
|
|
pointer->button_count > 0 &&
|
|
|
|
pointer->grab_serial == serial) {
|
|
|
|
focus = weston_surface_get_main_surface(pointer->focus->surface);
|
|
|
|
if ((focus == surface) &&
|
|
|
|
(kiosk_shell_grab_start_for_pointer_move(shsurf, pointer) ==
|
|
|
|
KIOSK_SHELL_GRAB_RESULT_ERROR))
|
|
|
|
wl_resource_post_no_memory(surface->resource);
|
|
|
|
}
|
|
|
|
else if (touch &&
|
|
|
|
touch->focus &&
|
|
|
|
touch->grab_serial == serial) {
|
|
|
|
focus = weston_surface_get_main_surface(touch->focus->surface);
|
|
|
|
if ((focus == surface) &&
|
|
|
|
(kiosk_shell_grab_start_for_touch_move(shsurf, touch) ==
|
|
|
|
KIOSK_SHELL_GRAB_RESULT_ERROR))
|
|
|
|
wl_resource_post_no_memory(surface->resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_resize(struct weston_desktop_surface *desktop_surface,
|
|
|
|
struct weston_seat *seat, uint32_t serial,
|
|
|
|
enum weston_desktop_surface_edge edges, void *shell)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_set_parent(struct weston_desktop_surface *desktop_surface,
|
|
|
|
struct weston_desktop_surface *parent,
|
|
|
|
void *shell)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
weston_desktop_surface_get_user_data(desktop_surface);
|
|
|
|
struct kiosk_shell_surface *shsurf_parent =
|
|
|
|
parent ? weston_desktop_surface_get_user_data(parent) : NULL;
|
|
|
|
|
|
|
|
kiosk_shell_surface_set_parent(shsurf, shsurf_parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_fullscreen_requested(struct weston_desktop_surface *desktop_surface,
|
|
|
|
bool fullscreen,
|
|
|
|
struct weston_output *output, void *shell)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
weston_desktop_surface_get_user_data(desktop_surface);
|
|
|
|
|
|
|
|
/* We should normally be able to ignore fullscreen requests for
|
|
|
|
* top-level surfaces, since we set them as fullscreen at creation
|
|
|
|
* time. However, xwayland surfaces set their internal WM state
|
|
|
|
* regardless of what the shell wants, so they may remove fullscreen
|
|
|
|
* state before informing weston-desktop of this request. Since we
|
|
|
|
* always want top-level surfaces to be fullscreen, we need to reapply
|
|
|
|
* the fullscreen state to force the correct xwayland WM state.
|
|
|
|
*
|
|
|
|
* TODO: Explore a model where the XWayland WM doesn't set the internal
|
|
|
|
* WM surface state itself, rather letting the shell make the decision.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!shsurf->parent || fullscreen)
|
|
|
|
kiosk_shell_surface_set_fullscreen(shsurf, output);
|
|
|
|
else
|
|
|
|
kiosk_shell_surface_set_normal(shsurf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_maximized_requested(struct weston_desktop_surface *desktop_surface,
|
|
|
|
bool maximized, void *shell)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
weston_desktop_surface_get_user_data(desktop_surface);
|
|
|
|
|
|
|
|
/* Since xwayland surfaces may have already applied the max/min states
|
|
|
|
* internally, reapply fullscreen to force the correct xwayland WM state.
|
|
|
|
* Also see comment in desktop_surface_fullscreen_requested(). */
|
|
|
|
if (!shsurf->parent)
|
|
|
|
kiosk_shell_surface_set_fullscreen(shsurf, NULL);
|
|
|
|
else if (maximized)
|
|
|
|
kiosk_shell_surface_set_maximized(shsurf);
|
|
|
|
else
|
|
|
|
kiosk_shell_surface_set_normal(shsurf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_minimized_requested(struct weston_desktop_surface *desktop_surface,
|
|
|
|
void *shell)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_ping_timeout(struct weston_desktop_client *desktop_client,
|
|
|
|
void *shell_)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_pong(struct weston_desktop_client *desktop_client,
|
|
|
|
void *shell_)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
desktop_surface_set_xwayland_position(struct weston_desktop_surface *desktop_surface,
|
2022-02-08 20:58:10 +03:00
|
|
|
struct weston_coord_global pos, void *shell)
|
2020-04-21 18:23:37 +03:00
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
weston_desktop_surface_get_user_data(desktop_surface);
|
|
|
|
|
2022-02-08 20:58:10 +03:00
|
|
|
shsurf->xwayland.pos = pos;
|
2020-04-21 18:23:37 +03:00
|
|
|
shsurf->xwayland.is_set = true;
|
|
|
|
}
|
|
|
|
|
2022-06-22 22:04:18 +03:00
|
|
|
static void
|
|
|
|
desktop_surface_get_position(struct weston_desktop_surface *desktop_surface,
|
|
|
|
int32_t *x, int32_t *y, void *shell)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
weston_desktop_surface_get_user_data(desktop_surface);
|
|
|
|
|
2022-02-04 02:47:41 +03:00
|
|
|
*x = shsurf->view->geometry.pos_offset.x;
|
|
|
|
*y = shsurf->view->geometry.pos_offset.y;
|
2022-06-22 22:04:18 +03:00
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
static const struct weston_desktop_api kiosk_shell_desktop_api = {
|
|
|
|
.struct_size = sizeof(struct weston_desktop_api),
|
|
|
|
.surface_added = desktop_surface_added,
|
|
|
|
.surface_removed = desktop_surface_removed,
|
|
|
|
.committed = desktop_surface_committed,
|
|
|
|
.move = desktop_surface_move,
|
|
|
|
.resize = desktop_surface_resize,
|
|
|
|
.set_parent = desktop_surface_set_parent,
|
|
|
|
.fullscreen_requested = desktop_surface_fullscreen_requested,
|
|
|
|
.maximized_requested = desktop_surface_maximized_requested,
|
|
|
|
.minimized_requested = desktop_surface_minimized_requested,
|
|
|
|
.ping_timeout = desktop_surface_ping_timeout,
|
|
|
|
.pong = desktop_surface_pong,
|
|
|
|
.set_xwayland_position = desktop_surface_set_xwayland_position,
|
2022-06-22 22:04:18 +03:00
|
|
|
.get_position = desktop_surface_get_position,
|
2020-04-21 18:23:37 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* kiosk_shell
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct kiosk_shell_output *
|
|
|
|
kiosk_shell_find_shell_output(struct kiosk_shell *shell,
|
|
|
|
struct weston_output *output)
|
|
|
|
{
|
|
|
|
struct kiosk_shell_output *shoutput;
|
|
|
|
|
|
|
|
wl_list_for_each(shoutput, &shell->output_list, link) {
|
|
|
|
if (shoutput->output == output)
|
|
|
|
return shoutput;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_activate_view(struct kiosk_shell *shell,
|
|
|
|
struct weston_view *view,
|
|
|
|
struct weston_seat *seat,
|
|
|
|
uint32_t flags)
|
|
|
|
{
|
|
|
|
struct weston_surface *main_surface =
|
|
|
|
weston_surface_get_main_surface(view->surface);
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
get_kiosk_shell_surface(main_surface);
|
2021-03-05 22:58:40 +03:00
|
|
|
struct kiosk_shell_seat *kiosk_seat =
|
|
|
|
get_kiosk_shell_seat(seat);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
2023-06-06 02:30:35 +03:00
|
|
|
if (!shsurf || !kiosk_seat)
|
2020-04-21 18:23:37 +03:00
|
|
|
return;
|
|
|
|
|
2023-06-06 02:30:35 +03:00
|
|
|
kiosk_shell_surface_activate(shsurf, kiosk_seat, flags);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_click_to_activate_binding(struct weston_pointer *pointer,
|
|
|
|
const struct timespec *time,
|
|
|
|
uint32_t button, void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell = data;
|
|
|
|
|
|
|
|
if (pointer->grab != &pointer->default_grab)
|
|
|
|
return;
|
|
|
|
if (pointer->focus == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
kiosk_shell_activate_view(shell, pointer->focus, pointer->seat,
|
|
|
|
WESTON_ACTIVATE_FLAG_CLICKED);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_touch_to_activate_binding(struct weston_touch *touch,
|
|
|
|
const struct timespec *time,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell = data;
|
|
|
|
|
|
|
|
if (touch->grab != &touch->default_grab)
|
|
|
|
return;
|
|
|
|
if (touch->focus == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
kiosk_shell_activate_view(shell, touch->focus, touch->seat,
|
|
|
|
WESTON_ACTIVATE_FLAG_NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_add_bindings(struct kiosk_shell *shell)
|
|
|
|
{
|
2021-10-04 15:54:43 +03:00
|
|
|
uint32_t mod = 0;
|
|
|
|
|
2022-11-22 14:48:13 +03:00
|
|
|
mod = weston_config_get_binding_modifier(shell->config, MODIFIER_SUPER);
|
2021-10-04 15:54:43 +03:00
|
|
|
|
2022-10-21 15:04:01 +03:00
|
|
|
weston_compositor_add_button_binding(shell->compositor, BTN_LEFT, 0,
|
2020-04-21 18:23:37 +03:00
|
|
|
kiosk_shell_click_to_activate_binding,
|
|
|
|
shell);
|
2022-10-21 15:04:01 +03:00
|
|
|
weston_compositor_add_button_binding(shell->compositor, BTN_RIGHT, 0,
|
2020-04-21 18:23:37 +03:00
|
|
|
kiosk_shell_click_to_activate_binding,
|
|
|
|
shell);
|
2022-10-21 15:04:01 +03:00
|
|
|
weston_compositor_add_touch_binding(shell->compositor, 0,
|
2020-04-21 18:23:37 +03:00
|
|
|
kiosk_shell_touch_to_activate_binding,
|
|
|
|
shell);
|
2021-10-04 15:54:43 +03:00
|
|
|
|
|
|
|
weston_install_debug_key_binding(shell->compositor, mod);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_handle_output_created(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell =
|
|
|
|
container_of(listener, struct kiosk_shell, output_created_listener);
|
|
|
|
struct weston_output *output = data;
|
|
|
|
|
|
|
|
kiosk_shell_output_create(shell, output);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_handle_output_resized(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell =
|
|
|
|
container_of(listener, struct kiosk_shell, output_resized_listener);
|
|
|
|
struct weston_output *output = data;
|
|
|
|
struct kiosk_shell_output *shoutput =
|
|
|
|
kiosk_shell_find_shell_output(shell, output);
|
|
|
|
struct weston_view *view;
|
|
|
|
|
|
|
|
kiosk_shell_output_recreate_background(shoutput);
|
|
|
|
|
|
|
|
wl_list_for_each(view, &shell->normal_layer.view_list.link,
|
|
|
|
layer_link.link) {
|
|
|
|
struct kiosk_shell_surface *shsurf;
|
|
|
|
if (view->output != output)
|
|
|
|
continue;
|
|
|
|
shsurf = get_kiosk_shell_surface(view->surface);
|
|
|
|
if (!shsurf)
|
|
|
|
continue;
|
|
|
|
kiosk_shell_surface_reconfigure_for_output(shsurf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_handle_output_moved(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell =
|
|
|
|
container_of(listener, struct kiosk_shell, output_moved_listener);
|
|
|
|
struct weston_output *output = data;
|
|
|
|
struct weston_view *view;
|
|
|
|
|
|
|
|
wl_list_for_each(view, &shell->background_layer.view_list.link,
|
|
|
|
layer_link.link) {
|
2022-11-09 23:28:15 +03:00
|
|
|
struct weston_coord_global pos;
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
if (view->output != output)
|
|
|
|
continue;
|
2022-11-09 23:28:15 +03:00
|
|
|
|
2023-07-18 21:51:07 +03:00
|
|
|
pos = weston_coord_global_add(
|
|
|
|
weston_view_get_pos_offset_global(view),
|
|
|
|
output->move);
|
2022-11-09 22:39:08 +03:00
|
|
|
weston_view_set_position(view, pos);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
wl_list_for_each(view, &shell->normal_layer.view_list.link,
|
|
|
|
layer_link.link) {
|
2022-11-09 23:28:15 +03:00
|
|
|
struct weston_coord_global pos;
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
if (view->output != output)
|
|
|
|
continue;
|
2022-11-09 23:28:15 +03:00
|
|
|
|
2023-07-18 21:51:07 +03:00
|
|
|
pos = weston_coord_global_add(
|
|
|
|
weston_view_get_pos_offset_global(view),
|
|
|
|
output->move);
|
2022-11-09 22:39:08 +03:00
|
|
|
weston_view_set_position(view, pos);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
kiosk_shell_handle_seat_created(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct weston_seat *seat = data;
|
2020-10-24 16:26:59 +03:00
|
|
|
struct kiosk_shell *shell =
|
|
|
|
container_of(listener, struct kiosk_shell, seat_created_listener);
|
|
|
|
kiosk_shell_seat_create(shell, seat);
|
2020-04-21 18:23:37 +03:00
|
|
|
}
|
|
|
|
|
2021-12-17 12:07:25 +03:00
|
|
|
static void
|
|
|
|
kiosk_shell_destroy_surfaces_on_layer(struct weston_layer *layer)
|
|
|
|
{
|
|
|
|
struct weston_view *view, *view_next;
|
|
|
|
|
|
|
|
wl_list_for_each_safe(view, view_next, &layer->view_list.link, layer_link.link) {
|
|
|
|
struct kiosk_shell_surface *shsurf =
|
|
|
|
get_kiosk_shell_surface(view->surface);
|
|
|
|
assert(shsurf);
|
|
|
|
kiosk_shell_surface_destroy(shsurf);
|
|
|
|
}
|
|
|
|
|
|
|
|
weston_layer_fini(layer);
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
static void
|
|
|
|
kiosk_shell_destroy(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell =
|
|
|
|
container_of(listener, struct kiosk_shell, destroy_listener);
|
|
|
|
struct kiosk_shell_output *shoutput, *tmp;
|
2020-10-24 16:26:59 +03:00
|
|
|
struct kiosk_shell_seat *shseat, *shseat_next;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
wl_list_remove(&shell->destroy_listener.link);
|
|
|
|
wl_list_remove(&shell->output_created_listener.link);
|
|
|
|
wl_list_remove(&shell->output_resized_listener.link);
|
|
|
|
wl_list_remove(&shell->output_moved_listener.link);
|
|
|
|
wl_list_remove(&shell->seat_created_listener.link);
|
2021-03-24 13:47:07 +03:00
|
|
|
wl_list_remove(&shell->transform_listener.link);
|
2024-05-22 12:51:18 +03:00
|
|
|
wl_list_remove(&shell->session_listener.link);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
wl_list_for_each_safe(shoutput, tmp, &shell->output_list, link) {
|
|
|
|
kiosk_shell_output_destroy(shoutput);
|
|
|
|
}
|
|
|
|
|
2021-12-17 12:07:25 +03:00
|
|
|
/* bg layer doesn't contain a weston_desktop_surface, and
|
|
|
|
* kiosk_shell_output_destroy() takes care of destroying it, we're just
|
|
|
|
* doing a weston_layer_fini() here as there might be multiple bg views */
|
|
|
|
weston_layer_fini(&shell->background_layer);
|
|
|
|
kiosk_shell_destroy_surfaces_on_layer(&shell->normal_layer);
|
|
|
|
kiosk_shell_destroy_surfaces_on_layer(&shell->inactive_layer);
|
|
|
|
|
2020-10-24 16:26:59 +03:00
|
|
|
wl_list_for_each_safe(shseat, shseat_next, &shell->seat_list, link) {
|
|
|
|
kiosk_shell_seat_destroy(shseat);
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
weston_desktop_destroy(shell->desktop);
|
|
|
|
|
|
|
|
free(shell);
|
|
|
|
}
|
|
|
|
|
2024-05-22 12:51:18 +03:00
|
|
|
static void
|
|
|
|
kiosk_shell_notify_session(struct wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell =
|
|
|
|
container_of(listener, struct kiosk_shell, session_listener);
|
|
|
|
struct kiosk_shell_seat *k_seat;
|
|
|
|
struct weston_compositor *compositor = data;
|
|
|
|
struct weston_seat *seat = get_kiosk_shell_first_seat(shell);
|
|
|
|
|
|
|
|
|
|
|
|
if (!compositor->session_active || !seat)
|
|
|
|
return;
|
|
|
|
|
|
|
|
k_seat = get_kiosk_shell_seat(seat);
|
|
|
|
if (k_seat->focused_surface) {
|
|
|
|
struct kiosk_shell_surface *current_focus =
|
|
|
|
get_kiosk_shell_surface(k_seat->focused_surface);
|
|
|
|
|
|
|
|
weston_view_activate_input(current_focus->view,
|
|
|
|
k_seat->seat,
|
|
|
|
WESTON_ACTIVATE_FLAG_NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
WL_EXPORT int
|
|
|
|
wet_shell_init(struct weston_compositor *ec,
|
|
|
|
int *argc, char *argv[])
|
|
|
|
{
|
|
|
|
struct kiosk_shell *shell;
|
|
|
|
struct weston_seat *seat;
|
|
|
|
struct weston_output *output;
|
2021-03-26 16:55:05 +03:00
|
|
|
const char *config_file;
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
shell = zalloc(sizeof *shell);
|
|
|
|
if (shell == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
shell->compositor = ec;
|
|
|
|
|
|
|
|
if (!weston_compositor_add_destroy_listener_once(ec,
|
|
|
|
&shell->destroy_listener,
|
|
|
|
kiosk_shell_destroy)) {
|
|
|
|
free(shell);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-24 13:47:07 +03:00
|
|
|
shell->transform_listener.notify = transform_handler;
|
|
|
|
wl_signal_add(&ec->transform_signal, &shell->transform_listener);
|
|
|
|
|
2021-03-26 16:55:05 +03:00
|
|
|
config_file = weston_config_get_name_from_env();
|
|
|
|
shell->config = weston_config_parse(config_file);
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
weston_layer_init(&shell->background_layer, ec);
|
|
|
|
weston_layer_init(&shell->normal_layer, ec);
|
2021-11-09 20:25:46 +03:00
|
|
|
weston_layer_init(&shell->inactive_layer, ec);
|
2020-04-21 18:23:37 +03:00
|
|
|
|
|
|
|
weston_layer_set_position(&shell->background_layer,
|
|
|
|
WESTON_LAYER_POSITION_BACKGROUND);
|
2021-11-09 20:25:46 +03:00
|
|
|
weston_layer_set_position(&shell->inactive_layer,
|
|
|
|
WESTON_LAYER_POSITION_HIDDEN);
|
2020-04-21 18:23:37 +03:00
|
|
|
/* We use the NORMAL layer position, so that xwayland surfaces, which
|
|
|
|
* are placed at NORMAL+1, are visible. */
|
|
|
|
weston_layer_set_position(&shell->normal_layer,
|
|
|
|
WESTON_LAYER_POSITION_NORMAL);
|
|
|
|
|
|
|
|
shell->desktop = weston_desktop_create(ec, &kiosk_shell_desktop_api,
|
|
|
|
shell);
|
|
|
|
if (!shell->desktop)
|
|
|
|
return -1;
|
|
|
|
|
2020-10-24 16:26:59 +03:00
|
|
|
wl_list_init(&shell->seat_list);
|
2020-04-21 18:23:37 +03:00
|
|
|
wl_list_for_each(seat, &ec->seat_list, link)
|
2020-10-24 16:26:59 +03:00
|
|
|
kiosk_shell_seat_create(shell, seat);
|
2020-04-21 18:23:37 +03:00
|
|
|
shell->seat_created_listener.notify = kiosk_shell_handle_seat_created;
|
|
|
|
wl_signal_add(&ec->seat_created_signal, &shell->seat_created_listener);
|
|
|
|
|
|
|
|
wl_list_init(&shell->output_list);
|
|
|
|
wl_list_for_each(output, &ec->output_list, link)
|
|
|
|
kiosk_shell_output_create(shell, output);
|
|
|
|
|
|
|
|
shell->output_created_listener.notify = kiosk_shell_handle_output_created;
|
|
|
|
wl_signal_add(&ec->output_created_signal, &shell->output_created_listener);
|
|
|
|
|
|
|
|
shell->output_resized_listener.notify = kiosk_shell_handle_output_resized;
|
|
|
|
wl_signal_add(&ec->output_resized_signal, &shell->output_resized_listener);
|
|
|
|
|
|
|
|
shell->output_moved_listener.notify = kiosk_shell_handle_output_moved;
|
|
|
|
wl_signal_add(&ec->output_moved_signal, &shell->output_moved_listener);
|
|
|
|
|
2024-05-22 12:51:18 +03:00
|
|
|
shell->session_listener.notify = kiosk_shell_notify_session;
|
|
|
|
wl_signal_add(&ec->session_signal, &shell->session_listener);
|
2021-03-24 13:38:59 +03:00
|
|
|
screenshooter_create(ec);
|
|
|
|
|
2020-04-21 18:23:37 +03:00
|
|
|
kiosk_shell_add_bindings(shell);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|