fix: popup position constrain not work for some app

This commit is contained in:
DreamMaoMao 2026-02-25 10:06:58 +08:00
parent a28647585f
commit 564df864bf
4 changed files with 118 additions and 47 deletions

View file

@ -3647,13 +3647,13 @@ void reapply_cursor_style(void) {
cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, cursor_size);
if(cursor_size > 0){
char size_str[16];
snprintf(size_str, sizeof(size_str), "%d", cursor_size);
if (cursor_size > 0) {
char size_str[16];
snprintf(size_str, sizeof(size_str), "%d", cursor_size);
setenv("XCURSOR_SIZE", size_str, 1);
}
if(config.cursor_theme){
if (config.cursor_theme) {
setenv("XCURSOR_THEME", config.cursor_theme, 1);
}

View file

@ -77,15 +77,6 @@ Monitor *output_from_wlr_output(struct wlr_output *wlr_output) {
return NULL;
}
Monitor *output_nearest_to(int32_t lx, int32_t ly) {
double closest_x, closest_y;
wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x,
&closest_y);
return output_from_wlr_output(
wlr_output_layout_output_at(output_layout, closest_x, closest_y));
}
bool output_is_usable(Monitor *m) { return m && m->wlr_output->enabled; }
static bool
@ -255,7 +246,7 @@ static void update_popup_position(struct dwl_input_method_popup *popup) {
cursor_rect = (struct wlr_box){0};
}
output = output_nearest_to(cursor_rect.x, cursor_rect.y);
output = get_monitor_nearest_to(cursor_rect.x, cursor_rect.y);
if (!output_is_usable(output)) {
return;
}

View file

@ -96,3 +96,12 @@ Monitor *xytomon(double x, double y) {
struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y);
return o ? o->data : NULL;
}
Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly) {
double closest_x, closest_y;
wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x,
&closest_y);
return output_from_wlr_output(
wlr_output_layout_output_at(output_layout, closest_x, closest_y));
}

View file

@ -486,6 +486,16 @@ typedef struct {
bool being_unmapped;
} LayerSurface;
typedef struct {
struct wlr_xdg_popup *wlr_popup;
Client *client;
LayerSurface *layer;
uint32_t type;
struct wl_listener destroy;
struct wl_listener commit;
struct wl_listener reposition;
} Popup;
typedef struct {
const char *symbol;
void (*arrange)(Monitor *);
@ -790,6 +800,7 @@ static Client *get_focused_stack_client(Client *sc);
static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc);
static void monitor_stop_skip_frame_timer(Monitor *m);
static int monitor_skip_frame_timeout_callback(void *data);
static Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly);
#include "data/static_keymap.h"
#include "dispatch/bind_declare.h"
@ -895,11 +906,8 @@ static KeyMode keymode = {
.isdefault = true,
};
static char *env_vars[] = {"DISPLAY",
"WAYLAND_DISPLAY",
"XDG_CURRENT_DESKTOP",
"XDG_SESSION_TYPE",
NULL};
static char *env_vars[] = {"DISPLAY", "WAYLAND_DISPLAY", "XDG_CURRENT_DESKTOP",
"XDG_SESSION_TYPE", NULL};
static struct {
enum wp_cursor_shape_device_v1_shape shape;
struct wlr_surface *surface;
@ -2545,37 +2553,107 @@ void destroydecoration(struct wl_listener *listener, void *data) {
wl_list_remove(&c->set_decoration_mode.link);
}
void commitpopup(struct wl_listener *listener, void *data) {
static void popup_unconstrain(Popup *popup) {
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
if (!wlr_popup || !wlr_popup->parent) {
return;
}
struct wlr_scene_node *parent_node = wlr_popup->parent->data;
if (!parent_node) {
wlr_log(WLR_ERROR, "Popup parent has no scene node");
return;
}
int parent_lx, parent_ly;
wlr_scene_node_coords(parent_node, &parent_lx, &parent_ly);
struct wlr_box *scheduled = &wlr_popup->scheduled.geometry;
int popup_lx = parent_lx + scheduled->x;
int popup_ly = parent_ly + scheduled->y;
Monitor *mon = get_monitor_nearest_to(popup_lx, popup_ly);
struct wlr_box usable = popup->type == LayerShell ? mon->m : mon->w;
struct wlr_box constraint_box = {
.x = usable.x - parent_lx,
.y = usable.y - parent_ly,
.width = usable.width,
.height = usable.height,
};
wlr_xdg_popup_unconstrain_from_box(wlr_popup, &constraint_box);
}
static void destroypopup(struct wl_listener *listener, void *data) {
Popup *popup = wl_container_of(listener, popup, destroy);
wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->reposition.link);
free(popup);
}
static void commitpopup(struct wl_listener *listener, void *data) {
Popup *popup = wl_container_of(listener, popup, commit);
struct wlr_surface *surface = data;
struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface);
LayerSurface *l = NULL;
struct wlr_xdg_popup *wkr_popup =
wlr_xdg_popup_try_from_wlr_surface(surface);
Client *c = NULL;
struct wlr_box box;
LayerSurface *l = NULL;
int32_t type = -1;
if (!popup || !popup->base->initial_commit)
if (!wkr_popup || !wkr_popup->base->initial_commit)
goto commitpopup_listen_free;
type = toplevel_from_wlr_surface(popup->base->surface, &c, &l);
if (!popup->parent || !popup->parent->data || type < 0)
goto commitpopup_listen_free;
wlr_scene_node_raise_to_top(popup->parent->data);
popup->base->surface->data =
wlr_scene_xdg_surface_create(popup->parent->data, popup->base);
if ((l && !l->mon) || (c && !c->mon)) {
wlr_xdg_popup_destroy(popup);
type = toplevel_from_wlr_surface(wkr_popup->base->surface, &c, &l);
if (!wkr_popup->parent || !wkr_popup->parent->data || type < 0) {
wlr_xdg_popup_destroy(wkr_popup);
goto commitpopup_listen_free;
}
box = type == LayerShell ? l->mon->m : c->mon->w;
box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x);
box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y);
wlr_xdg_popup_unconstrain_from_box(popup, &box);
wlr_scene_node_raise_to_top(wkr_popup->parent->data);
wkr_popup->base->surface->data =
wlr_scene_xdg_surface_create(wkr_popup->parent->data, wkr_popup->base);
if ((l && !l->mon) || (c && !c->mon)) {
wlr_xdg_popup_destroy(wkr_popup);
goto commitpopup_listen_free;
}
popup->client = c;
popup->layer = l;
popup->type = type;
popup->wlr_popup = wkr_popup;
popup_unconstrain(popup);
commitpopup_listen_free:
wl_list_remove(&listener->link);
free(listener);
wl_list_remove(&popup->commit.link);
popup->commit.notify = NULL;
}
static void repositionpopup(struct wl_listener *listener, void *data) {
Popup *popup = wl_container_of(listener, popup, reposition);
popup_unconstrain(popup);
}
static void createpopup(struct wl_listener *listener, void *data) {
struct wlr_xdg_popup *wlr_popup = data;
Popup *popup = calloc(1, sizeof(Popup));
if (!popup)
return;
popup->destroy.notify = destroypopup;
wl_signal_add(&wlr_popup->events.destroy, &popup->destroy);
popup->commit.notify = commitpopup;
wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
popup->reposition.notify = repositionpopup;
wl_signal_add(&wlr_popup->events.reposition, &popup->reposition);
}
void createdecoration(struct wl_listener *listener, void *data) {
@ -3165,13 +3243,6 @@ void createpointerconstraint(struct wl_listener *listener, void *data) {
&pointer_constraint->destroy, destroypointerconstraint);
}
void createpopup(struct wl_listener *listener, void *data) {
/* This event is raised when a client (either xdg-shell or layer-shell)
* creates a new popup. */
struct wlr_xdg_popup *popup = data;
LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
}
void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) {
if (active_constraint == constraint)
return;