decompose wl_backend.c: extract wl_popup.c

This commit is contained in:
Window Maker 2026-06-02 16:01:22 +02:00
parent c46adc93c5
commit ac4aa4fe4d
3 changed files with 186 additions and 171 deletions

View File

@ -189,6 +189,7 @@ wmaker_SOURCES += \
backend/wayland/wl_pointer_focus.c \
backend/wayland/wl_grab.c \
backend/wayland/wl_keyboard.c \
backend/wayland/wl_popup.c \
backend/wayland/wl_xwayland.c \
backend/wayland/wl_dock.c \
backend/wayland/wl_input_fwd.c

View File

@ -295,6 +295,7 @@ void wl_update_pointer_focus(uint32_t time_msec);
void wl_pointer_warp_to(int x, int y);
/* wmaker-popup-v1 helper — defined in protocol section below. */
void wmaker_popup_apply(struct wl_toplevel_view *view);
extern void wmaker_popup_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id);
/* Phase 14: pointer event handler forward declarations. */
extern void handle_pointer_motion(struct wl_listener *listener, void *data);
/* Phase 24: click-to-focus helper — defined in Phase 13 pointer section. */
@ -788,178 +789,7 @@ handle_new_toplevel_decoration(struct wl_listener *listener, void *data)
}
}
/* ------------------------------------------------------------------ */
/* wmaker-popup-v1 protocol — client-driven popup positioning */
/* ------------------------------------------------------------------ */
static void
wmaker_popup_handle_destroy(struct wl_client *client,
struct wl_resource *resource)
{
(void)client;
wl_resource_destroy(resource);
}
static void
wmaker_popup_handle_set_parent(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *parent_resource)
{
(void)client;
struct wl_toplevel_view *view = wl_resource_get_user_data(resource);
if (!view) return;
if (parent_resource) {
view->popup_parent = wlr_xdg_toplevel_from_resource(parent_resource);
} else {
view->popup_parent = NULL;
}
wwarning("wmaker_popup: set_parent view=%p parent=%p", (void*)view,
(void*)view->popup_parent);
}
static void
wmaker_popup_handle_set_position(struct wl_client *client,
struct wl_resource *resource,
int32_t x, int32_t y)
{
(void)client;
struct wl_toplevel_view *view = wl_resource_get_user_data(resource);
wwarning("wmaker_popup: set_position view=%p (%d,%d)", (void*)view, x, y);
if (!view) return;
view->popup_x = (int)x;
view->popup_y = (int)y;
wmaker_popup_apply(view);
}
static const struct wmaker_popup_v1_interface wmaker_popup_impl = {
.destroy = wmaker_popup_handle_destroy,
.set_parent = wmaker_popup_handle_set_parent,
.set_position = wmaker_popup_handle_set_position,
};
static void
wmaker_popup_resource_destroy(struct wl_resource *resource)
{
struct wl_toplevel_view *view = wl_resource_get_user_data(resource);
if (view && view->popup == resource)
view->popup = NULL;
}
void
wmaker_popup_apply(struct wl_toplevel_view *view)
{
if (!view || !view->popup) return;
/* If a parent was set, translate the requested position into screen
* coordinates by adding the parent toplevel's current position. */
int target_x = view->popup_x;
int target_y = view->popup_y;
if (view->popup_parent) {
struct wl_toplevel_view *parent_view =
wl_find_view_by_xdg_surface(view->popup_parent->base);
if (parent_view) {
target_x += parent_view->x;
target_y += parent_view->y;
}
}
int dx = target_x - view->x;
int dy = target_y - view->y;
wwarning("wmaker_popup_apply: view=%p (%d,%d)->(%d,%d) frame_id=0x%lx scene_node=%p",
(void*)view, view->x, view->y, target_x, target_y,
(unsigned long)view->frame_id, (void*)view->scene_node);
view->x = target_x;
view->y = target_y;
/* If a frame_buf wraps this view, move it via the WM's window-move
* path so the frame and its tree node update consistently. */
if (view->frame_id) {
struct wl_frame_buf *fb = frame_buf_find(view->frame_id);
if (fb) {
fb->x += dx;
fb->y += dy;
if (fb->tree) {
wlr_scene_node_set_position(&fb->tree->node, fb->x, fb->y);
/* Raise above siblings so popups appear over their parent */
wlr_scene_node_raise_to_top(&fb->tree->node);
wwarning("popup_apply: raised frame tree id=0x%lx to top, parent=%p",
(unsigned long)view->id, (void*)fb->tree->node.parent);
} else if (fb->scene_buf) {
wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y);
wlr_scene_node_raise_to_top(&fb->scene_buf->node);
}
view->frame_rel_x = 0;
view->frame_rel_y = 0;
}
} else if (view->scene_node) {
wlr_scene_node_set_position(&view->scene_node->node,
view->x, view->y);
wlr_scene_node_raise_to_top(&view->scene_node->node);
wwarning("popup_apply: raised scene_node id=0x%lx to top",
(unsigned long)view->id);
}
}
static void
wmaker_popup_manager_handle_destroy(struct wl_client *client,
struct wl_resource *resource)
{
(void)client;
wl_resource_destroy(resource);
}
static void
wmaker_popup_manager_handle_get_popup(struct wl_client *client,
struct wl_resource *manager_resource,
uint32_t id,
struct wl_resource *toplevel_resource)
{
(void)manager_resource;
struct wlr_xdg_toplevel *xdg_top =
wlr_xdg_toplevel_from_resource(toplevel_resource);
if (!xdg_top) {
wl_resource_post_error(manager_resource, 0,
"wmaker_popup: invalid xdg_toplevel resource");
return;
}
struct wl_toplevel_view *view =
wl_find_view_by_xdg_surface(xdg_top->base);
struct wl_resource *resource = wl_resource_create(client,
&wmaker_popup_v1_interface, 1, id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &wmaker_popup_impl,
view, wmaker_popup_resource_destroy);
if (view)
view->popup = resource;
}
static const struct wmaker_popup_manager_v1_interface wmaker_popup_manager_impl = {
.destroy = wmaker_popup_manager_handle_destroy,
.get_popup = wmaker_popup_manager_handle_get_popup,
};
static void
wmaker_popup_manager_bind(struct wl_client *client, void *data,
uint32_t version, uint32_t id)
{
(void)data;
struct wl_resource *resource = wl_resource_create(client,
&wmaker_popup_manager_v1_interface,
version > 1 ? 1 : (int)version, id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &wmaker_popup_manager_impl,
NULL, NULL);
}
/*
* handle_xdg_toplevel_initial_commit -- wlroots 0.19 requires that the

View File

@ -0,0 +1,184 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#include "wmaker-popup-v1-server-protocol.h"
#include "wl_types.h"
/* Forward declarations */
struct wl_toplevel_view *wl_find_view_by_xdg_surface(struct wlr_xdg_surface *surf);
struct wl_frame_buf *frame_buf_find(WNativeWindow id);
/* ------------------------------------------------------------------ */
/* wmaker-popup-v1 protocol — client-driven popup positioning */
/* ------------------------------------------------------------------ */
static void
wmaker_popup_handle_destroy(struct wl_client *client,
struct wl_resource *resource)
{
(void)client;
wl_resource_destroy(resource);
}
static void
wmaker_popup_handle_set_parent(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *parent_resource)
{
(void)client;
struct wl_toplevel_view *view = wl_resource_get_user_data(resource);
if (!view) return;
if (parent_resource) {
view->popup_parent = wlr_xdg_toplevel_from_resource(parent_resource);
} else {
view->popup_parent = NULL;
}
wwarning("wmaker_popup: set_parent view=%p parent=%p", (void*)view,
(void*)view->popup_parent);
}
static void
wmaker_popup_handle_set_position(struct wl_client *client,
struct wl_resource *resource,
int32_t x, int32_t y)
{
(void)client;
struct wl_toplevel_view *view = wl_resource_get_user_data(resource);
wwarning("wmaker_popup: set_position view=%p (%d,%d)", (void*)view, x, y);
if (!view) return;
view->popup_x = (int)x;
view->popup_y = (int)y;
wmaker_popup_apply(view);
}
static const struct wmaker_popup_v1_interface wmaker_popup_impl = {
.destroy = wmaker_popup_handle_destroy,
.set_parent = wmaker_popup_handle_set_parent,
.set_position = wmaker_popup_handle_set_position,
};
static void
wmaker_popup_resource_destroy(struct wl_resource *resource)
{
struct wl_toplevel_view *view = wl_resource_get_user_data(resource);
if (view && view->popup == resource)
view->popup = NULL;
}
void
wmaker_popup_apply(struct wl_toplevel_view *view)
{
if (!view || !view->popup) return;
int target_x = view->popup_x;
int target_y = view->popup_y;
if (view->popup_parent) {
struct wl_toplevel_view *parent_view =
wl_find_view_by_xdg_surface(view->popup_parent->base);
if (parent_view) {
target_x += parent_view->x;
target_y += parent_view->y;
}
}
int dx = target_x - view->x;
int dy = target_y - view->y;
wwarning("wmaker_popup_apply: view=%p (%d,%d)->(%d,%d) frame_id=0x%lx scene_node=%p",
(void*)view, view->x, view->y, target_x, target_y,
(unsigned long)view->frame_id, (void*)view->scene_node);
view->x = target_x;
view->y = target_y;
if (view->frame_id) {
struct wl_frame_buf *fb = frame_buf_find(view->frame_id);
if (fb) {
fb->x += dx;
fb->y += dy;
if (fb->tree) {
wlr_scene_node_set_position(&fb->tree->node, fb->x, fb->y);
wlr_scene_node_raise_to_top(&fb->tree->node);
wwarning("popup_apply: raised frame tree id=0x%lx to top, parent=%p",
(unsigned long)view->id, (void*)fb->tree->node.parent);
} else if (fb->scene_buf) {
wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y);
wlr_scene_node_raise_to_top(&fb->scene_buf->node);
}
view->frame_rel_x = 0;
view->frame_rel_y = 0;
}
} else if (view->scene_node) {
wlr_scene_node_set_position(&view->scene_node->node,
view->x, view->y);
wlr_scene_node_raise_to_top(&view->scene_node->node);
wwarning("popup_apply: raised scene_node id=0x%lx to top",
(unsigned long)view->id);
}
}
static void
wmaker_popup_manager_handle_destroy(struct wl_client *client,
struct wl_resource *resource)
{
(void)client;
wl_resource_destroy(resource);
}
static void
wmaker_popup_manager_handle_get_popup(struct wl_client *client,
struct wl_resource *manager_resource,
uint32_t id,
struct wl_resource *toplevel_resource)
{
(void)manager_resource;
struct wlr_xdg_toplevel *xdg_top =
wlr_xdg_toplevel_from_resource(toplevel_resource);
if (!xdg_top) {
wl_resource_post_error(manager_resource, 0,
"wmaker_popup: invalid xdg_toplevel resource");
return;
}
struct wl_toplevel_view *view =
wl_find_view_by_xdg_surface(xdg_top->base);
struct wl_resource *resource = wl_resource_create(client,
&wmaker_popup_v1_interface, 1, id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &wmaker_popup_impl,
view, wmaker_popup_resource_destroy);
if (view)
view->popup = resource;
}
static const struct wmaker_popup_manager_v1_interface wmaker_popup_manager_impl = {
.destroy = wmaker_popup_manager_handle_destroy,
.get_popup = wmaker_popup_manager_handle_get_popup,
};
void
wmaker_popup_manager_bind(struct wl_client *client, void *data,
uint32_t version, uint32_t id)
{
(void)data;
struct wl_resource *resource = wl_resource_create(client,
&wmaker_popup_manager_v1_interface,
version > 1 ? 1 : (int)version, id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &wmaker_popup_manager_impl,
NULL, NULL);
}