323 lines
8.3 KiB
C
323 lines
8.3 KiB
C
/*
|
|
* wview_wl.c - Wayland view backend for WINGs
|
|
*
|
|
* Views are logical layout containers in Wayland mode.
|
|
* No X11 dependencies. Rendering is handled by frame_paint (pixman buffers).
|
|
*/
|
|
|
|
#include "WINGsP.h"
|
|
#include <pixman.h>
|
|
|
|
/* Synthetic window IDs for Wayland views (distinct from frame buffer IDs) */
|
|
#define WL_VIEW_ID_BASE 0x20000000
|
|
static unsigned int wl_view_next_id = WL_VIEW_ID_BASE;
|
|
|
|
/* Callback set by WM backend to commit frame_buf after paint */
|
|
void (*W_ViewCommitBackingFn)(unsigned long id) = NULL;
|
|
|
|
/* Simple view lookup table (ID → W_View*) */
|
|
#define VIEW_TABLE_SIZE 256
|
|
static struct { Window id; W_View *view; void *backing; } view_table[VIEW_TABLE_SIZE];
|
|
|
|
static void view_table_put(Window id, W_View *view)
|
|
{
|
|
unsigned idx = ((unsigned)id) % VIEW_TABLE_SIZE;
|
|
for (int i = 0; i < VIEW_TABLE_SIZE; i++) {
|
|
unsigned slot = (idx + i) % VIEW_TABLE_SIZE;
|
|
if (view_table[slot].id == 0 || view_table[slot].id == id) {
|
|
view_table[slot].id = id;
|
|
view_table[slot].view = view;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
W_View *W_GetViewForWindow(Window id)
|
|
{
|
|
unsigned idx = ((unsigned)id) % VIEW_TABLE_SIZE;
|
|
for (int i = 0; i < VIEW_TABLE_SIZE; i++) {
|
|
unsigned slot = (idx + i) % VIEW_TABLE_SIZE;
|
|
if (view_table[slot].id == id)
|
|
return view_table[slot].view;
|
|
if (view_table[slot].id == 0) {
|
|
wwarning("W_GetViewForWindow: id=0x%lx NOT FOUND (slot %u empty)", (unsigned long)id, slot);
|
|
return NULL;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* Get/set backing pixman image for a view ID */
|
|
void *W_GetViewBacking(Window id)
|
|
{
|
|
unsigned idx = ((unsigned)id) % VIEW_TABLE_SIZE;
|
|
for (int i = 0; i < VIEW_TABLE_SIZE; i++) {
|
|
unsigned slot = (idx + i) % VIEW_TABLE_SIZE;
|
|
if (view_table[slot].id == id)
|
|
return view_table[slot].backing;
|
|
if (view_table[slot].id == 0)
|
|
return NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void W_SetViewBacking(Window id, void *img)
|
|
{
|
|
unsigned idx = ((unsigned)id) % VIEW_TABLE_SIZE;
|
|
for (int i = 0; i < VIEW_TABLE_SIZE; i++) {
|
|
unsigned slot = (idx + i) % VIEW_TABLE_SIZE;
|
|
if (view_table[slot].id == id) {
|
|
view_table[slot].backing = img;
|
|
return;
|
|
}
|
|
if (view_table[slot].id == 0)
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void view_table_remove(Window id)
|
|
{
|
|
unsigned idx = ((unsigned)id) % VIEW_TABLE_SIZE;
|
|
for (int i = 0; i < VIEW_TABLE_SIZE; i++) {
|
|
unsigned slot = (idx + i) % VIEW_TABLE_SIZE;
|
|
if (view_table[slot].id == id) {
|
|
view_table[slot].id = 0;
|
|
view_table[slot].view = NULL;
|
|
view_table[slot].backing = NULL;
|
|
return;
|
|
}
|
|
if (view_table[slot].id == 0)
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void *wl_screen_init(W_Screen *scr)
|
|
{
|
|
(void)scr;
|
|
return scr; /* use scr as token */
|
|
}
|
|
|
|
static void wl_screen_fini(void *vctx)
|
|
{
|
|
(void)vctx;
|
|
}
|
|
|
|
static void wl_create_root(void *vctx, W_View *view)
|
|
{
|
|
(void)vctx;
|
|
|
|
view->window = (Window)wl_view_next_id++;
|
|
view_table_put(view->window, view);
|
|
/* Default screen size — the WM backend will update this */
|
|
view->size.width = 1920;
|
|
view->size.height = 1080;
|
|
}
|
|
|
|
static void wl_realize(void *vctx, W_View *view)
|
|
{
|
|
(void)vctx;
|
|
|
|
/* Assign a synthetic ID so W_DispatchMessage doesn't skip this view */
|
|
view->window = (Window)wl_view_next_id++;
|
|
view_table_put(view->window, view);
|
|
|
|
/* Allocate a backing pixman image for this view */
|
|
int w = view->size.width > 0 ? view->size.width : 1;
|
|
int h = view->size.height > 0 ? view->size.height : 1;
|
|
pixman_image_t *img = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0);
|
|
W_SetViewBacking(view->window, img);
|
|
}
|
|
|
|
static void wl_noop(void *vctx, W_View *view)
|
|
{
|
|
(void)vctx;
|
|
(void)view;
|
|
}
|
|
|
|
static void wl_redisplay(void *vctx, W_View *view);
|
|
static void wl_map_subviews(void *vctx, W_View *view);
|
|
|
|
static void wl_map(void *vctx, W_View *view)
|
|
{
|
|
(void)vctx;
|
|
/* Set mapped early so redisplay doesn't bail out */
|
|
view->flags.mapped = 1;
|
|
/* Only trigger redisplay for top-level views (dialogs) */
|
|
if (view->flags.topLevel && view->flags.realized) {
|
|
wl_redisplay(vctx, view);
|
|
wl_map_subviews(vctx, view);
|
|
}
|
|
}
|
|
|
|
static void wl_map_subviews(void *vctx, W_View *view)
|
|
{
|
|
W_View *child = view->childrenList;
|
|
while (child) {
|
|
if (child->flags.realized) {
|
|
child->flags.mapped = 1;
|
|
wl_redisplay(vctx, child);
|
|
}
|
|
/* Recurse into grandchildren */
|
|
if (child->childrenList)
|
|
wl_map_subviews(vctx, child);
|
|
child = child->nextSister;
|
|
}
|
|
}
|
|
|
|
static void wl_noop_move(void *vctx, W_View *view, int x, int y)
|
|
{
|
|
(void)vctx;
|
|
(void)view;
|
|
(void)x;
|
|
(void)y;
|
|
}
|
|
|
|
static void wl_noop_resize(void *vctx, W_View *view, unsigned int w, unsigned int h)
|
|
{
|
|
(void)vctx;
|
|
(void)view;
|
|
(void)w;
|
|
(void)h;
|
|
}
|
|
|
|
static void wl_noop_reparent(void *vctx, W_View *view, W_View *newParent, int x, int y)
|
|
{
|
|
(void)vctx;
|
|
(void)view;
|
|
(void)newParent;
|
|
(void)x;
|
|
(void)y;
|
|
}
|
|
|
|
static void wl_destroy(void *vctx, W_View *view)
|
|
{
|
|
(void)vctx;
|
|
(void)view;
|
|
/* Nothing to free — synthetic ID only */
|
|
}
|
|
|
|
static void wl_set_background_color(void *vctx, W_View *view, WMColor *color)
|
|
{
|
|
(void)vctx;
|
|
(void)view;
|
|
(void)color;
|
|
/* Background is handled by pixman rendering in frame_paint */
|
|
}
|
|
|
|
static void wl_set_cursor(void *vctx, W_View *view, Cursor cursor)
|
|
{
|
|
(void)vctx;
|
|
(void)view;
|
|
(void)cursor;
|
|
/* Cursor is managed by wlroots seat */
|
|
}
|
|
|
|
static void wl_redisplay(void *vctx, W_View *view)
|
|
{
|
|
WMEvent ev;
|
|
|
|
(void)vctx;
|
|
|
|
if (!view->flags.mapped)
|
|
return;
|
|
|
|
/* Fill background color */
|
|
pixman_image_t *backing = (pixman_image_t *)W_GetViewBacking(view->window);
|
|
if (backing && view->backColor) {
|
|
pixman_color_t bg;
|
|
bg.red = view->backColor->color.red;
|
|
bg.green = view->backColor->color.green;
|
|
bg.blue = view->backColor->color.blue;
|
|
bg.alpha = view->backColor->alpha ? view->backColor->alpha : 0xFFFF;
|
|
pixman_image_fill_rectangles(PIXMAN_OP_SRC, backing, &bg,
|
|
1, &(pixman_rectangle16_t){0, 0, view->size.width, view->size.height});
|
|
} else if (backing) {
|
|
/* Default: light grey background */
|
|
pixman_color_t bg = {0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF};
|
|
pixman_image_fill_rectangles(PIXMAN_OP_SRC, backing, &bg,
|
|
1, &(pixman_rectangle16_t){0, 0, view->size.width, view->size.height});
|
|
}
|
|
|
|
memset(&ev, 0, sizeof(ev));
|
|
ev.type = WME_EXPOSE;
|
|
ev.window = (WNativeWindow)view->window;
|
|
ev.u.expose.window = (WNativeWindow)view->window;
|
|
ev.u.expose.count = 0;
|
|
ev._x11_raw = NULL;
|
|
|
|
WMHandleEvent(&ev);
|
|
|
|
/* Composite this view's backing into its parent's backing */
|
|
if (view->parent) {
|
|
pixman_image_t *src = (pixman_image_t *)W_GetViewBacking(view->window);
|
|
pixman_image_t *dst = (pixman_image_t *)W_GetViewBacking(view->parent->window);
|
|
if (src && dst) {
|
|
pixman_image_composite32(PIXMAN_OP_OVER, src, NULL, dst,
|
|
0, 0, 0, 0,
|
|
view->pos.x, view->pos.y,
|
|
view->size.width, view->size.height);
|
|
}
|
|
}
|
|
|
|
/* Notify WM backend to commit the top-level view's backing buffer */
|
|
/* Walk up to find the top-level view */
|
|
W_View *top = view;
|
|
while (top->parent && !top->flags.topLevel)
|
|
top = top->parent;
|
|
|
|
extern void (*W_ViewCommitBackingFn)(unsigned long id);
|
|
if (W_ViewCommitBackingFn)
|
|
W_ViewCommitBackingFn((unsigned long)top->window);
|
|
}
|
|
|
|
static WMPoint wl_get_screen_position(void *vctx, W_View *view)
|
|
{
|
|
W_Screen *scr = (W_Screen *)vctx;
|
|
int x = 0, y = 0;
|
|
W_View *v;
|
|
|
|
/* Walk up the view tree accumulating positions */
|
|
for (v = view; v && v != scr->rootView; v = v->parent) {
|
|
x += v->pos.x;
|
|
y += v->pos.y;
|
|
}
|
|
|
|
return wmkpoint(x, y);
|
|
}
|
|
|
|
static Bool wl_selection_acquire(void *vctx, W_View *view, Atom selection, Time timestamp)
|
|
{
|
|
(void)vctx; (void)view; (void)selection; (void)timestamp;
|
|
/* TODO: implement via wl_data_device */
|
|
return True;
|
|
}
|
|
|
|
static void wl_selection_release(void *vctx, W_View *view, Atom selection)
|
|
{
|
|
(void)vctx; (void)view; (void)selection;
|
|
}
|
|
|
|
const W_ViewBackend W_ViewBackendWL = {
|
|
.screen_init = wl_screen_init,
|
|
.screen_fini = wl_screen_fini,
|
|
.create_root = wl_create_root,
|
|
.realize = wl_realize,
|
|
.map = wl_map,
|
|
.unmap = wl_noop,
|
|
.map_subviews = wl_map_subviews,
|
|
.unmap_subviews = wl_noop,
|
|
.move = wl_noop_move,
|
|
.resize = wl_noop_resize,
|
|
.raise = wl_noop,
|
|
.lower = wl_noop,
|
|
.reparent = wl_noop_reparent,
|
|
.destroy = wl_destroy,
|
|
.set_background_color = wl_set_background_color,
|
|
.set_cursor = wl_set_cursor,
|
|
.redisplay = wl_redisplay,
|
|
.get_screen_position = wl_get_screen_position,
|
|
.selection_acquire = wl_selection_acquire,
|
|
.selection_release = wl_selection_release,
|
|
.platform_init = NULL,
|
|
};
|