Compare commits

...

13 Commits

Author SHA1 Message Date
bonsaiiV
479064ce89
Merge branch 'master' into workspace-critierion 2024-02-22 18:42:10 +00:00
llyyr
d6150b6bb0 input/text_input: parent wlr_box may be uninitialized 2024-02-20 16:19:40 +01:00
Access
7c11c463a3
text_input: Implement input-method popups
Co-authored-by: tadeokondrak <me@tadeo.ca>
2024-02-20 10:53:20 +01:00
Aleksei Bavshin
d19810eba8 xdg-activation: distinguish activation and urgency requests
Check if the app that requested a token has provided a valid input
serial and a focused surface. Downgrade activation request to urgency
otherwise.

This is mostly in line with what other Wayland compositors decided to
do, and offers a better security than the original logic.
2024-02-17 00:54:30 -07:00
Ronan Pigott
f6d22f8e68 launcher: track the seat in the launcher ctx
This is a more suitable place to track the requesting seat, since we are
able to respond appropriately to destroy notifications.
2024-02-17 00:54:30 -07:00
Simon Ser
541e6e260c Drop unnecessary includes from sway/server.h 2024-02-15 15:56:36 +01:00
Simon Ser
ca40663d42 Fix build with wlroots DRM backend disabled
The header is not installed by wlroots when the DRM backend is
disabled. We don't need it here, so don't include it.

Closes: https://github.com/swaywm/sway/issues/7943
2024-02-15 09:44:12 -05:00
Kirill Primak
7a2ff7ba81 view: drop ext_foreign_destroy
It's not used and causes a crash when a view is destroyed.
2024-02-12 19:05:13 +01:00
Alexander Orzechowski
09c360d503 layer_shell: Handle popups through popup descriptor
We tried to synchronize layer shell popups with the parent layer shell
on commits, but this is subtly wrong because we would only update
the position for one layer shell that was committed, but not any other
layer that might be affected. By moving handling to the scene descriptor
we can iterate all popups and ensure they are synchronized.
2024-02-12 19:19:22 +03:00
Alexander Orzechowski
1846944f04 xdg_shell: Extract struct for popup descriptor 2024-02-12 19:19:22 +03:00
Alexander Orzechowski
1dc661af17 layer_shell: Arrange popups even if exclusive zone doesn't change 2024-02-12 19:19:22 +03:00
Merlin Lex
1b5515400d ext-foreign-toplevel-list: Implement protocol
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4543
2024-02-12 15:36:44 +01:00
Simon Ser
88b2abf5f2 config: use format_str() instead of hand-rolled snprintf() 2024-02-08 16:11:24 -05:00
20 changed files with 410 additions and 57 deletions

View File

@ -3,14 +3,18 @@
#include <stdlib.h>
#include <wayland-server-core.h>
#include "sway/input/seat.h"
struct launcher_ctx {
pid_t pid;
char *fallback_name;
struct wlr_xdg_activation_token_v1 *token;
struct wl_listener token_destroy;
struct sway_seat *seat;
struct wl_listener seat_destroy;
bool activated;
bool had_focused_surface;
struct sway_node *node;
struct wl_listener node_destroy;

View File

@ -2,6 +2,7 @@
#define _SWAY_TRANSACTION_H
#include <stdint.h>
#include <stdbool.h>
#include <wlr/types/wlr_scene.h>
/**
* Transactions enable us to perform atomic layout updates.
@ -58,4 +59,6 @@ bool transaction_notify_view_ready_by_serial(struct sway_view *view,
bool transaction_notify_view_ready_by_geometry(struct sway_view *view,
double x, double y, int width, int height);
void arrange_popups(struct wlr_scene_tree *popups);
#endif

View File

@ -21,18 +21,21 @@ struct sway_input_method_relay {
struct sway_seat *seat;
struct wl_list text_inputs; // sway_text_input::link
struct wl_list input_popups; // sway_input_popup::link
struct wlr_input_method_v2 *input_method; // doesn't have to be present
struct wl_listener text_input_new;
struct wl_listener input_method_new;
struct wl_listener input_method_commit;
struct wl_listener input_method_new_popup_surface;
struct wl_listener input_method_grab_keyboard;
struct wl_listener input_method_destroy;
struct wl_listener input_method_keyboard_grab_destroy;
};
struct sway_text_input {
struct sway_input_method_relay *relay;

View File

@ -0,0 +1,20 @@
#ifndef _SWAY_INPUT_TEXT_INPUT_POPUP_H
#define _SWAY_INPUT_TEXT_INPUT_POPUP_H
#include "sway/tree/view.h"
struct sway_input_popup {
struct sway_input_method_relay *relay;
struct wlr_scene_tree *scene_tree;
struct sway_popup_desc desc;
struct wlr_input_popup_surface_v2 *popup_surface;
struct wl_list link;
struct wl_listener popup_destroy;
struct wl_listener popup_surface_commit;
struct wl_listener focused_surface_unmap;
};
#endif

View File

@ -3,6 +3,7 @@
#include <stdbool.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include "sway/tree/view.h"
struct sway_layer_surface {
struct wl_listener map;
@ -14,10 +15,12 @@ struct sway_layer_surface {
bool mapped;
struct wlr_scene_tree *popups;
struct sway_popup_desc desc;
struct sway_output *output;
struct wlr_scene_layer_surface_v1 *scene;
struct wlr_scene_tree *tree;
struct wlr_scene_tree *popups;
struct wlr_layer_surface_v1 *layer_surface;
};

View File

@ -2,23 +2,6 @@
#define _SWAY_SERVER_H
#include <stdbool.h>
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_input_method_v2.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h>
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_relative_pointer_v1.h>
#include <wlr/types/wlr_session_lock_v1.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_text_input_v3.h>
#include <wlr/types/wlr_xdg_shell.h>
#include "config.h"
#include "list.h"
#include "sway/desktop/idle_inhibit_v1.h"
@ -116,6 +99,7 @@ struct sway_server {
struct wl_listener output_power_manager_set_mode;
struct wlr_input_method_manager_v2 *input_method;
struct wlr_text_input_manager_v3 *text_input;
struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list;
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
struct wlr_content_type_manager_v1 *content_type_manager_v1;
struct wlr_data_control_manager_v1 *data_control_manager_v1;

View File

@ -84,6 +84,8 @@ struct sway_view {
// transaction state. Updated on every commit.
struct wlr_box geometry;
struct wlr_ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel;
struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel;
struct wl_listener foreign_activate_request;
struct wl_listener foreign_fullscreen_request;
@ -174,6 +176,11 @@ struct sway_xwayland_unmanaged {
};
#endif
struct sway_popup_desc {
struct wlr_scene_node *relative;
struct sway_view *view;
};
struct sway_xdg_popup {
struct sway_view *view;
@ -181,6 +188,8 @@ struct sway_xdg_popup {
struct wlr_scene_tree *xdg_surface_tree;
struct wlr_xdg_popup *wlr_xdg_popup;
struct sway_popup_desc desc;
struct wl_listener surface_commit;
struct wl_listener new_popup;
struct wl_listener destroy;
@ -233,6 +242,11 @@ void view_set_activated(struct sway_view *view, bool activated);
*/
void view_request_activate(struct sway_view *view, struct sway_seat *seat);
/*
* Called when the view requests urgent state
*/
void view_request_urgent(struct sway_view *view);
/**
* If possible, instructs the client to change their decoration mode.
*/
@ -284,6 +298,8 @@ struct sway_view *view_from_wlr_xwayland_surface(
#endif
struct sway_view *view_from_wlr_surface(struct wlr_surface *surface);
void view_update_app_id(struct sway_view *view);
/**
* Re-read the view's title property and update any relevant title bars.
* The force argument makes it recreate the title bars even if the title hasn't

View File

@ -352,13 +352,7 @@ static char *config_path(const char *prefix, const char *config_folder) {
if (!prefix || !prefix[0] || !config_folder || !config_folder[0]) {
return NULL;
}
const char *filename = "config";
size_t size = 3 + strlen(prefix) + strlen(config_folder) + strlen(filename);
char *path = calloc(size, sizeof(char));
snprintf(path, size, "%s/%s/%s", prefix, config_folder, filename);
return path;
return format_str("%s/%s/config", prefix, config_folder);
}
static char *get_config_path(void) {
@ -368,10 +362,7 @@ static char *get_config_path(void) {
const char *config_home = getenv("XDG_CONFIG_HOME");
if ((config_home == NULL || config_home[0] == '\0') && home != NULL) {
size_t size_fallback = 1 + strlen(home) + strlen("/.config");
config_home_fallback = calloc(size_fallback, sizeof(char));
if (config_home_fallback != NULL)
snprintf(config_home_fallback, size_fallback, "%s/.config", home);
config_home_fallback = format_str("%s/.config", home);
config_home = config_home_fallback;
}

View File

@ -67,6 +67,9 @@ void launcher_ctx_destroy(struct launcher_ctx *ctx) {
}
wl_list_remove(&ctx->node_destroy.link);
wl_list_remove(&ctx->token_destroy.link);
if (ctx->seat) {
wl_list_remove(&ctx->seat_destroy.link);
}
wl_list_remove(&ctx->link);
wlr_xdg_activation_token_v1_destroy(ctx->token);
free(ctx->fallback_name);
@ -213,6 +216,8 @@ struct launcher_ctx *launcher_ctx_create(struct wlr_xdg_activation_token_v1 *tok
ctx->fallback_name = strdup(fallback_name);
ctx->token = token;
ctx->node = node;
// Having surface set means that the focus check in wlroots has passed
ctx->had_focused_surface = token->surface != NULL;
ctx->node_destroy.notify = ctx_handle_node_destroy;
wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy);
@ -227,6 +232,12 @@ struct launcher_ctx *launcher_ctx_create(struct wlr_xdg_activation_token_v1 *tok
return ctx;
}
static void launch_ctx_handle_seat_destroy(struct wl_listener *listener, void *data) {
struct launcher_ctx *ctx = wl_container_of(listener, ctx, seat_destroy);
ctx->seat = NULL;
wl_list_remove(&ctx->seat_destroy.link);
}
// Creates a context with a new token for the internal launcher
struct launcher_ctx *launcher_ctx_create_internal(void) {
struct sway_seat *seat = input_manager_current_seat();
@ -238,13 +249,15 @@ struct launcher_ctx *launcher_ctx_create_internal(void) {
struct wlr_xdg_activation_token_v1 *token =
wlr_xdg_activation_token_v1_create(server.xdg_activation_v1);
token->seat = seat->wlr_seat;
struct launcher_ctx *ctx = launcher_ctx_create(token, &ws->node);
if (!ctx) {
wlr_xdg_activation_token_v1_destroy(token);
return NULL;
}
ctx->seat = seat;
ctx->seat_destroy.notify = launch_ctx_handle_seat_destroy;
wl_signal_add(&seat->wlr_seat->events.destroy, &ctx->seat_destroy);
return ctx;
}

View File

@ -4,7 +4,9 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_xdg_shell.h>
#include "log.h"
#include "sway/scene_descriptor.h"
#include "sway/desktop/transaction.h"
@ -16,7 +18,6 @@
#include "sway/server.h"
#include "sway/tree/arrange.h"
#include "sway/tree/workspace.h"
#include <wlr/types/wlr_scene.h>
struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
struct wlr_surface *surface) {
@ -85,6 +86,8 @@ void arrange_layers(struct sway_output *output) {
sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
output->usable_area = usable_area;
arrange_output(output);
} else {
arrange_popups(root->layers.popup);
}
}
@ -120,10 +123,21 @@ static struct sway_layer_surface *sway_layer_surface_create(
return NULL;
}
surface->desc.relative = &scene->tree->node;
if (!scene_descriptor_assign(&popups->node,
SWAY_SCENE_DESC_POPUP, &surface->desc)) {
sway_log(SWAY_ERROR, "Failed to allocate a popup scene descriptor");
wlr_scene_node_destroy(&popups->node);
free(surface);
return NULL;
}
surface->tree = scene->tree;
surface->scene = scene;
surface->layer_surface = scene->layer_surface;
surface->popups = popups;
surface->layer_surface->data = surface;
return surface;
}
@ -197,6 +211,8 @@ static void handle_node_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&layer->node_destroy.link);
wl_list_remove(&layer->output_destroy.link);
layer->layer_surface->data = NULL;
free(layer);
}
@ -222,10 +238,6 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
arrange_layers(surface->output);
transaction_commit_dirty();
}
int lx, ly;
wlr_scene_node_coords(&surface->scene->tree->node, &lx, &ly);
wlr_scene_node_set_position(&surface->popups->node, lx, ly);
}
static void handle_map(struct wl_listener *listener, void *data) {

View File

@ -12,6 +12,8 @@
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_compositor.h>

View File

@ -606,21 +606,15 @@ static void arrange_output(struct sway_output *output, int width, int height) {
}
}
static void arrange_popup(struct wlr_scene_tree *popup) {
void arrange_popups(struct wlr_scene_tree *popups) {
struct wlr_scene_node *node;
wl_list_for_each(node, &popup->children, link) {
struct sway_xdg_popup *popup = scene_descriptor_try_get(node,
wl_list_for_each(node, &popups->children, link) {
struct sway_popup_desc *popup = scene_descriptor_try_get(node,
SWAY_SCENE_DESC_POPUP);
// the popup layer may have popups from layer_shell surfaces, in this
// case those don't have a scene descriptor, so lets skip those here.
if (popup) {
struct wlr_scene_tree *tree = popup->view->content_tree;
int lx, ly;
wlr_scene_node_coords(&tree->node, &lx, &ly);
wlr_scene_node_set_position(&popup->scene_tree->node, lx, ly);
}
int lx, ly;
wlr_scene_node_coords(popup->relative, &lx, &ly);
wlr_scene_node_set_position(node, lx, ly);
}
}
@ -679,7 +673,7 @@ static void arrange_root(struct sway_root *root) {
}
}
arrange_popup(root->layers.popup);
arrange_popups(root->layers.popup);
}
/**

View File

@ -97,8 +97,11 @@ static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup,
return NULL;
}
popup->desc.relative = &view->content_tree->node;
popup->desc.view = view;
if (!scene_descriptor_assign(&popup->scene_tree->node,
SWAY_SCENE_DESC_POPUP, popup)) {
SWAY_SCENE_DESC_POPUP, &popup->desc)) {
sway_log(SWAY_ERROR, "Failed to allocate a popup scene descriptor");
wlr_scene_node_destroy(&popup->scene_tree->node);
free(popup);
@ -337,6 +340,7 @@ static void handle_set_app_id(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, set_app_id);
struct sway_view *view = &xdg_shell_view->view;
view_update_app_id(view);
view_execute_criteria(view);
}

View File

@ -9,6 +9,7 @@
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_cursor_shape_v1.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_relative_pointer_v1.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_tablet_v2.h>
#include <wlr/types/wlr_tablet_pad.h>
@ -90,9 +91,9 @@ struct sway_node *node_at_coords(
}
if (!con) {
struct sway_xdg_popup *popup =
struct sway_popup_desc *popup =
scene_descriptor_try_get(current, SWAY_SCENE_DESC_POPUP);
if (popup) {
if (popup && popup->view) {
con = popup->view->container;
}
}

View File

@ -2,7 +2,14 @@
#include <stdlib.h>
#include "log.h"
#include "sway/input/seat.h"
#include "sway/scene_descriptor.h"
#include "sway/tree/root.h"
#include "sway/tree/view.h"
#include "sway/output.h"
#include "sway/input/text_input.h"
#include "sway/input/text_input_popup.h"
#include "sway/layers.h"
static void input_popup_update(struct sway_input_popup *popup);
static struct sway_text_input *relay_get_focusable_text_input(
struct sway_input_method_relay *relay) {
@ -102,6 +109,7 @@ static void handle_im_destroy(struct wl_listener *listener, void *data) {
input_method_destroy);
struct wlr_input_method_v2 *context = data;
assert(context == relay->input_method);
wl_list_remove(&relay->input_method_new_popup_surface.link);
relay->input_method = NULL;
struct sway_text_input *text_input = relay_get_focused_text_input(relay);
if (text_input) {
@ -133,6 +141,11 @@ static void relay_send_im_state(struct sway_input_method_relay *relay,
input->current.content_type.hint,
input->current.content_type.purpose);
}
struct sway_input_popup *popup;
wl_list_for_each(popup, &relay->input_popups, link) {
// send_text_input_rectangle is called in this function
input_popup_update(popup);
}
wlr_input_method_v2_send_done(input_method);
// TODO: pass intent, display popup size
}
@ -255,6 +268,215 @@ static void relay_handle_text_input(struct wl_listener *listener,
sway_text_input_create(relay, wlr_text_input);
}
static void input_popup_update(struct sway_input_popup *popup) {
struct sway_text_input *text_input =
relay_get_focused_text_input(popup->relay);
if (text_input == NULL || text_input->input->focused_surface == NULL) {
return;
}
if (popup->scene_tree != NULL) {
wlr_scene_node_destroy(&popup->scene_tree->node);
popup->scene_tree = NULL;
}
if (popup->desc.relative != NULL) {
wlr_scene_node_destroy(popup->desc.relative);
popup->desc.relative = NULL;
}
popup->desc.view = NULL;
if (!popup->popup_surface->surface->mapped) {
return;
}
wlr_scene_node_destroy(&popup->scene_tree->node);
wlr_scene_node_destroy(popup->desc.relative);
popup->scene_tree = NULL;
bool cursor_rect = text_input->input->current.features
& WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE;
struct wlr_surface *focused_surface = text_input->input->focused_surface;
struct wlr_box cursor_area = text_input->input->current.cursor_rectangle;
struct wlr_box output_box;
struct wlr_box parent = {0};
struct wlr_layer_surface_v1 *layer_surface =
wlr_layer_surface_v1_try_from_wlr_surface(focused_surface);
struct wlr_scene_tree *relative_parent;
struct wlr_box geo = {0};
popup->scene_tree = wlr_scene_subsurface_tree_create(root->layers.popup, popup->popup_surface->surface);
if (layer_surface != NULL) {
struct sway_layer_surface *layer =
layer_surface->data;
if (layer == NULL) {
return;
}
relative_parent = layer->scene->tree;
struct wlr_output *output = layer->layer_surface->output;
wlr_output_layout_get_box(root->output_layout, output, &output_box);
int lx, ly;
wlr_scene_node_coords(&layer->tree->node, &lx, &ly);
parent.x = lx;
parent.y = ly;
popup->desc.view = NULL;
} else {
struct sway_view *view = view_from_wlr_surface(focused_surface);
relative_parent = view->scene_tree;
geo = view->geometry;
int lx, ly;
wlr_scene_node_coords(&view->scene_tree->node, &lx, &ly);
struct wlr_output *output = wlr_output_layout_output_at(root->output_layout,
view->container->pending.content_x + view->geometry.x,
view->container->pending.content_y + view->geometry.y);
wlr_output_layout_get_box(root->output_layout, output, &output_box);
parent.x = lx;
parent.y = ly;
parent.width = view->geometry.width;
parent.height = view->geometry.height;
popup->desc.view = view;
}
struct wlr_scene_tree *relative = wlr_scene_tree_create(relative_parent);
popup->desc.relative = &relative->node;
if (!scene_descriptor_assign(&popup->scene_tree->node,
SWAY_SCENE_DESC_POPUP, &popup->desc)) {
wlr_scene_node_destroy(&popup->scene_tree->node);
popup->scene_tree = NULL;
return;
}
if (!cursor_rect) {
cursor_area.x = 0;
cursor_area.y = 0;
cursor_area.width = parent.width;
cursor_area.height = parent.height;
}
int popup_width = popup->popup_surface->surface->current.width;
int popup_height = popup->popup_surface->surface->current.height;
int x1 = parent.x + cursor_area.x;
int x2 = parent.x + cursor_area.x + cursor_area.width;
int y1 = parent.y + cursor_area.y;
int y2 = parent.y + cursor_area.y + cursor_area.height;
int x = x1;
int y = y2;
int available_right = output_box.x + output_box.width - x1;
int available_left = x2 - output_box.x;
if (available_right < popup_width && available_left > available_right) {
x = x2 - popup_width;
}
int available_down = output_box.y + output_box.height - y2;
int available_up = y1 - output_box.y;
if (available_down < popup_height && available_up > available_down) {
y = y1 - popup_height;
}
wlr_scene_node_set_position(&relative->node, x - parent.x - geo.x, y - parent.y - geo.y);
if (cursor_rect) {
struct wlr_box box = {
.x = x1 - x,
.y = y1 - y,
.width = cursor_area.width,
.height = cursor_area.height,
};
wlr_input_popup_surface_v2_send_text_input_rectangle(
popup->popup_surface, &box);
}
wlr_scene_node_set_position(&popup->scene_tree->node, x - geo.x, y - geo.y);
}
static void input_popup_set_focus(struct sway_input_popup *popup,
struct wlr_surface *surface) {
wl_list_remove(&popup->focused_surface_unmap.link);
if (surface == NULL) {
wl_list_init(&popup->focused_surface_unmap.link);
input_popup_update(popup);
return;
}
struct wlr_layer_surface_v1 *layer_surface =
wlr_layer_surface_v1_try_from_wlr_surface(surface);
if (layer_surface != NULL) {
wl_signal_add(
&layer_surface->surface->events.unmap, &popup->focused_surface_unmap);
input_popup_update(popup);
return;
}
struct sway_view *view = view_from_wlr_surface(surface);
wl_signal_add(&view->events.unmap, &popup->focused_surface_unmap);
}
static void handle_im_popup_destroy(struct wl_listener *listener, void *data) {
struct sway_input_popup *popup =
wl_container_of(listener, popup, popup_destroy);
wl_list_remove(&popup->focused_surface_unmap.link);
wl_list_remove(&popup->popup_surface_commit.link);
wl_list_remove(&popup->popup_destroy.link);
wl_list_remove(&popup->link);
free(popup);
}
static void handle_im_popup_surface_commit(struct wl_listener *listener,
void *data) {
struct sway_input_popup *popup =
wl_container_of(listener, popup, popup_surface_commit);
input_popup_update(popup);
}
static void handle_im_focused_surface_unmap(
struct wl_listener *listener, void *data) {
struct sway_input_popup *popup =
wl_container_of(listener, popup, focused_surface_unmap);
input_popup_update(popup);
}
static void handle_im_new_popup_surface(struct wl_listener *listener,
void *data) {
struct sway_input_method_relay *relay = wl_container_of(listener, relay,
input_method_new_popup_surface);
struct sway_input_popup *popup = calloc(1, sizeof(*popup));
popup->relay = relay;
popup->popup_surface = data;
popup->popup_surface->data = popup;
wl_signal_add(
&popup->popup_surface->events.destroy, &popup->popup_destroy);
popup->popup_destroy.notify = handle_im_popup_destroy;
wl_signal_add(&popup->popup_surface->surface->events.commit,
&popup->popup_surface_commit);
popup->popup_surface_commit.notify = handle_im_popup_surface_commit;
wl_list_init(&popup->focused_surface_unmap.link);
popup->focused_surface_unmap.notify = handle_im_focused_surface_unmap;
struct sway_text_input *text_input = relay_get_focused_text_input(relay);
if (text_input != NULL) {
input_popup_set_focus(popup, text_input->input->focused_surface);
} else {
input_popup_set_focus(popup, NULL);
}
wl_list_insert(&relay->input_popups, &popup->link);
}
static void text_input_send_enter(struct sway_text_input *text_input,
struct wlr_surface *surface) {
wlr_text_input_v3_send_enter(text_input->input, surface);
struct sway_input_popup *popup;
wl_list_for_each(popup, &text_input->relay->input_popups, link) {
input_popup_set_focus(popup, surface);
}
}
static void relay_handle_input_method(struct wl_listener *listener,
void *data) {
struct sway_input_method_relay *relay = wl_container_of(listener, relay,
@ -280,10 +502,13 @@ static void relay_handle_input_method(struct wl_listener *listener,
wl_signal_add(&relay->input_method->events.destroy,
&relay->input_method_destroy);
relay->input_method_destroy.notify = handle_im_destroy;
wl_signal_add(&relay->input_method->events.new_popup_surface,
&relay->input_method_new_popup_surface);
relay->input_method_new_popup_surface.notify = handle_im_new_popup_surface;
struct sway_text_input *text_input = relay_get_focusable_text_input(relay);
if (text_input) {
wlr_text_input_v3_send_enter(text_input->input,
text_input_send_enter(text_input,
text_input->pending_focused_surface);
text_input_set_pending_focused_surface(text_input, NULL);
}
@ -293,6 +518,7 @@ void sway_input_method_relay_init(struct sway_seat *seat,
struct sway_input_method_relay *relay) {
relay->seat = seat;
wl_list_init(&relay->text_inputs);
wl_list_init(&relay->input_popups);
relay->text_input_new.notify = relay_handle_text_input;
wl_signal_add(&server.text_input->events.text_input,

View File

@ -1,6 +1,7 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_session_lock_v1.h>
#include "log.h"
#include "sway/input/cursor.h"
#include "sway/input/keyboard.h"

View File

@ -8,24 +8,32 @@
#include <wlr/backend/headless.h>
#include <wlr/backend/multi.h>
#include <wlr/config.h>
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_content_type_v1.h>
#include <wlr/types/wlr_cursor_shape_v1.h>
#include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_drm.h>
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_fractional_scale_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h>
#include <wlr/types/wlr_pointer_constraints_v1.h>
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_relative_pointer_v1.h>
#include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_security_context_v1.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_session_lock_v1.h>
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_tablet_v2.h>
@ -60,6 +68,7 @@
#define SWAY_XDG_SHELL_VERSION 2
#define SWAY_LAYER_SHELL_VERSION 4
#define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1
bool allow_unsupported_gpu = false;
@ -93,6 +102,7 @@ static bool is_privileged(const struct wl_global *global) {
global == server.output_manager_v1->global ||
global == server.output_power_manager_v1->global ||
global == server.input_method->global ||
global == server.foreign_toplevel_list->global ||
global == server.foreign_toplevel_manager->global ||
global == server.data_control_manager_v1->global ||
global == server.screencopy_manager_v1->global ||
@ -289,6 +299,8 @@ bool server_init(struct sway_server *server) {
&server->output_power_manager_set_mode);
server->input_method = wlr_input_method_manager_v2_create(server->wl_display);
server->text_input = wlr_text_input_manager_v3_create(server->wl_display);
server->foreign_toplevel_list =
wlr_ext_foreign_toplevel_list_v1_create(server->wl_display, SWAY_FOREIGN_TOPLEVEL_LIST_VERSION);
server->foreign_toplevel_manager =
wlr_foreign_toplevel_manager_v1_create(server->wl_display);

View File

@ -4,6 +4,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_subcompositor.h>

View File

@ -4,6 +4,8 @@
#include <wayland-server-core.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_subcompositor.h>
@ -410,6 +412,12 @@ void view_request_activate(struct sway_view *view, struct sway_seat *seat) {
transaction_commit_dirty();
}
void view_request_urgent(struct sway_view *view) {
if (config->focus_on_window_activation != FOWA_NONE) {
view_set_urgent(view, true);
}
}
void view_set_csd_from_server(struct sway_view *view, bool enabled) {
sway_log(SWAY_DEBUG, "Telling view %p to set CSD to %i", view, enabled);
if (view->xdg_decoration) {
@ -582,6 +590,14 @@ static struct sway_workspace *select_workspace(struct sway_view *view) {
return NULL;
}
static void update_ext_foreign_toplevel(struct sway_view *view) {
struct wlr_ext_foreign_toplevel_handle_v1_state toplevel_state = {
.app_id = view_get_app_id(view),
.title = view_get_title(view),
};
wlr_ext_foreign_toplevel_handle_v1_update_state(view->ext_foreign_toplevel, &toplevel_state);
}
static bool should_focus(struct sway_view *view) {
struct sway_seat *seat = input_manager_current_seat();
struct sway_container *prev_con = seat_get_focused_container(seat);
@ -751,6 +767,13 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
}
}
struct wlr_ext_foreign_toplevel_handle_v1_state foreign_toplevel_state = {
.app_id = view_get_app_id(view),
.title = view_get_title(view),
};
view->ext_foreign_toplevel =
wlr_ext_foreign_toplevel_handle_v1_create(server.foreign_toplevel_list, &foreign_toplevel_state);
view->foreign_toplevel =
wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager);
view->foreign_activate_request.notify = handle_foreign_activate_request;
@ -828,6 +851,10 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
input_manager_set_focus(&view->container->node);
}
if (view->ext_foreign_toplevel) {
update_ext_foreign_toplevel(view);
}
const char *app_id;
const char *class;
if ((app_id = view_get_app_id(view)) != NULL) {
@ -847,6 +874,11 @@ void view_unmap(struct sway_view *view) {
view->urgent_timer = NULL;
}
if (view->ext_foreign_toplevel) {
wlr_ext_foreign_toplevel_handle_v1_destroy(view->ext_foreign_toplevel);
view->ext_foreign_toplevel = NULL;
}
if (view->foreign_toplevel) {
wlr_foreign_toplevel_handle_v1_destroy(view->foreign_toplevel);
view->foreign_toplevel = NULL;
@ -1014,6 +1046,18 @@ static size_t parse_title_format(struct sway_view *view, char *buffer) {
return len;
}
void view_update_app_id(struct sway_view *view) {
const char *app_id = view_get_app_id(view);
if (view->foreign_toplevel && app_id) {
wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, app_id);
}
if (view->ext_foreign_toplevel) {
update_ext_foreign_toplevel(view);
}
}
void view_update_title(struct sway_view *view, bool force) {
const char *title = view_get_title(view);
@ -1060,6 +1104,10 @@ void view_update_title(struct sway_view *view, bool force) {
if (view->foreign_toplevel && title) {
wlr_foreign_toplevel_handle_v1_set_title(view->foreign_toplevel, title);
}
if (view->ext_foreign_toplevel) {
update_ext_foreign_toplevel(view);
}
}
bool view_is_visible(struct sway_view *view) {

View File

@ -1,4 +1,5 @@
#include <wlr/types/wlr_xdg_activation_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
#include "sway/desktop/launcher.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
@ -17,11 +18,15 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener,
return;
}
struct launcher_ctx *ctx = event->token->data;
if (ctx == NULL) {
return;
}
if (!xdg_surface->surface->mapped) {
// This is a startup notification. If we are tracking it, the data
// field is a launcher_ctx.
struct launcher_ctx *ctx = event->token->data;
if (!ctx || ctx->activated) {
if (ctx->activated) {
// This ctx has already been activated and cannot be used again
// for a startup notification. It will be destroyed
return;
@ -32,9 +37,19 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener,
return;
}
struct wlr_seat *wlr_seat = event->token->seat;
struct sway_seat *seat = wlr_seat ? wlr_seat->data : NULL;
view_request_activate(view, seat);
// This is an activation request. If this context is internal we have ctx->seat.
struct sway_seat *seat = ctx->seat;
if (!seat) {
// Otherwise, use the seat indicated by the launcher client in set_serial
seat = ctx->token->seat ? ctx->token->seat->data : NULL;
}
if (seat && ctx->had_focused_surface) {
view_request_activate(view, seat);
} else {
// The token is valid, but cannot be used to activate a window
view_request_urgent(view);
}
}
void xdg_activation_v1_handle_new_token(struct wl_listener *listener, void *data) {