wayland: implement dockapp rendering inside dock icons
XWayland dockapps (wmclock, etc.) now render their content inside the dock icon tile instead of in a separate window. Key changes: - wl_props.c: implement wl_prop_get_wm_hints for XWayland surfaces, reading xcb_icccm_wm_hints_t to detect WithdrawnState dockapps - appicon.c: for is_dockapp windows, use client_win as icon_win - icon.c: capture icon_window pixels via XGetImage with XShape mask for transparency, skip surface embedding when image is captured - wl_icon.c: create_rimage_from_drawable handles X11 Window IDs via XGetImage, applies XShape bounding rectangles as alpha mask - wl_stubs.c: pixmap_get_size returns actual view dimensions - wl_window.c: map XWayland dockapp windows and reparent icon_window child into main window for compositing
This commit is contained in:
parent
1728c38fbe
commit
b6ad1df42e
|
|
@ -146,6 +146,9 @@ void create_appicon_for_application(WApplication *wapp, WWindow *wwin)
|
|||
if (!wapp->app_icon) {
|
||||
/* Create the icon */
|
||||
wapp->app_icon = wAppIconCreate(wapp->main_window_desc);
|
||||
if (wapp->app_icon->icon->icon_win == WM_NATIVE_NONE &&
|
||||
wapp->main_window_desc->flags.is_dockapp)
|
||||
wapp->app_icon->icon->icon_win = wapp->main_window_desc->client_win;
|
||||
wIconUpdate(wapp->app_icon->icon);
|
||||
|
||||
/* Now, paint the icon */
|
||||
|
|
@ -1119,7 +1122,9 @@ static void create_appicon_from_dock(WWindow *wwin, WApplication *wapp, WNativeW
|
|||
|
||||
wapp->app_icon->running = 1;
|
||||
wapp->app_icon->icon->owner = mainw;
|
||||
if (mainw->wm_hints && (mainw->wm_hints->flags & WMH_ICON_WINDOW_HINT))
|
||||
if (mainw->flags.is_dockapp)
|
||||
wapp->app_icon->icon->icon_win = mainw->client_win;
|
||||
else if (mainw->wm_hints && (mainw->wm_hints->flags & WMH_ICON_WINDOW_HINT))
|
||||
wapp->app_icon->icon->icon_win = mainw->wm_hints->icon_window;
|
||||
|
||||
/* Update the icon images */
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@
|
|||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
#include <pixman.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/extensions/shape.h>
|
||||
#include <wraster.h>
|
||||
#include "../../screen.h"
|
||||
#include "../../framewin.h"
|
||||
#include "../../window.h"
|
||||
|
|
@ -64,7 +68,7 @@ wl_icon_paint(WIcon *icon)
|
|||
for (int col = 0; col < size && col < fb->width; col++) {
|
||||
int si = (row * tile->width + col) * (has_alpha ? 4 : 3);
|
||||
unsigned char r = tsrc[si], g = tsrc[si+1], b = tsrc[si+2];
|
||||
unsigned char a = has_alpha ? tsrc[si+3] : 0xFF;
|
||||
unsigned char a = 0xFF; (void)has_alpha;
|
||||
dst[row * stride + col] = ((uint32_t)a << 24) | ((uint32_t)r << 16)
|
||||
| ((uint32_t)g << 8) | (uint32_t)b;
|
||||
}
|
||||
|
|
@ -172,7 +176,7 @@ wl_appicon_paint(WAppIcon *aicon)
|
|||
for (int col = 0; col < size && col < fb->width; col++) {
|
||||
int si = (row * tile->width + col) * (has_alpha ? 4 : 3);
|
||||
unsigned char r = src[si], g = src[si+1], b = src[si+2];
|
||||
unsigned char a = has_alpha ? src[si+3] : 0xFF;
|
||||
unsigned char a = 0xFF; (void)has_alpha;
|
||||
dst[row * stride + col] = ((uint32_t)a << 24) | ((uint32_t)r << 16) |
|
||||
((uint32_t)g << 8) | (uint32_t)b;
|
||||
}
|
||||
|
|
@ -397,7 +401,8 @@ void wl_drawer_icon_paint(WAppIcon *aicon)
|
|||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
|
||||
/* Create an RImage by reading pixels from a frame_buf's pixman image */
|
||||
/* Create an RImage by reading pixels from a frame_buf's pixman image,
|
||||
* or via XGetImage for X11 window IDs (XWayland dockapps). */
|
||||
void *
|
||||
wl_create_rimage_from_drawable(void *rcontext, WMDrawable drawable)
|
||||
{
|
||||
|
|
@ -405,6 +410,59 @@ wl_create_rimage_from_drawable(void *rcontext, WMDrawable drawable)
|
|||
if (!drawable)
|
||||
return NULL;
|
||||
|
||||
/* X11 window ID (XWayland): capture via XGetImage */
|
||||
if ((unsigned long)drawable < 0x10000000 && wl_state.x_display) {
|
||||
Window xwin = (Window)(unsigned long)drawable;
|
||||
WScreen *scr = wScreenWithNumber(0);
|
||||
/* Ensure the window is mapped so we can capture its pixels */
|
||||
XMapWindow(wl_state.x_display, xwin);
|
||||
XFlush(wl_state.x_display);
|
||||
XWindowAttributes attr;
|
||||
if (XGetWindowAttributes(wl_state.x_display, xwin, &attr) &&
|
||||
attr.width > 0 && attr.height > 0) {
|
||||
XImage *ximg = XGetImage(wl_state.x_display, xwin,
|
||||
0, 0, attr.width, attr.height, AllPlanes, ZPixmap);
|
||||
if (ximg) {
|
||||
RImage *res = RCreateImageFromXImage(scr ? scr->rcontext : NULL, ximg, NULL);
|
||||
XDestroyImage(ximg);
|
||||
/* Apply XShape mask: only pixels within the shape
|
||||
* bounding region are visible (dockapp convention). */
|
||||
if (res) {
|
||||
int count = 0, ordering;
|
||||
XRectangle *rects = XShapeGetRectangles(wl_state.x_display,
|
||||
xwin, ShapeBounding, &count, &ordering);
|
||||
if (rects && count > 0) {
|
||||
int iw = res->width, ih = res->height;
|
||||
int bpp = (res->format == RRGBAFormat) ? 4 : 3;
|
||||
RImage *masked = RCreateImage(iw, ih, 1);
|
||||
if (masked) {
|
||||
/* Start fully transparent */
|
||||
memset(masked->data, 0, iw * ih * 4);
|
||||
/* Copy pixels inside shape rects */
|
||||
for (int r = 0; r < count; r++) {
|
||||
int rx = rects[r].x, ry = rects[r].y;
|
||||
int rw = rects[r].width, rh = rects[r].height;
|
||||
for (int row = ry; row < ry + rh && row < ih; row++) {
|
||||
if (row < 0) continue;
|
||||
for (int col = rx; col < rx + rw && col < iw; col++) {
|
||||
if (col < 0) continue;
|
||||
unsigned char *s = res->data + (row * iw + col) * bpp;
|
||||
unsigned char *d = masked->data + (row * iw + col) * 4;
|
||||
d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
RReleaseImage(res);
|
||||
res = masked;
|
||||
}
|
||||
XFree(rects);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pixman_image_t *pimg = NULL;
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)drawable);
|
||||
if (fb && fb->image) {
|
||||
|
|
@ -478,4 +536,3 @@ wl_icon_update_pixmap(WIcon *icon)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/xwayland.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#include "../../screen.h"
|
||||
#include "wl_types.h"
|
||||
|
||||
|
|
@ -75,7 +76,26 @@ wl_prop_get_normal_hints(WNativeWindow win, WNormalHints *out, int *pre_icccm)
|
|||
}
|
||||
|
||||
WWMHints *
|
||||
wl_prop_get_wm_hints(WNativeWindow win) { (void)win; return NULL; }
|
||||
wl_prop_get_wm_hints(WNativeWindow win)
|
||||
{
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v || !v->xw_surface || !v->xw_surface->hints)
|
||||
return NULL;
|
||||
|
||||
xcb_icccm_wm_hints_t *xh = v->xw_surface->hints;
|
||||
WWMHints *out = wmalloc(sizeof(WWMHints));
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
out->flags = xh->flags;
|
||||
out->input = (xh->flags & XCB_ICCCM_WM_HINT_INPUT) ? xh->input : 1;
|
||||
out->initial_state = (xh->flags & XCB_ICCCM_WM_HINT_STATE) ? xh->initial_state : WMH_NORMAL_STATE;
|
||||
out->icon_pixmap = (xh->flags & XCB_ICCCM_WM_HINT_ICON_PIXMAP) ? (WNativeWindow)xh->icon_pixmap : WM_NATIVE_NONE;
|
||||
out->icon_window = (xh->flags & XCB_ICCCM_WM_HINT_ICON_WINDOW) ? (WNativeWindow)xh->icon_window : WM_NATIVE_NONE;
|
||||
out->icon_mask = (xh->flags & XCB_ICCCM_WM_HINT_ICON_MASK) ? (WNativeWindow)xh->icon_mask : WM_NATIVE_NONE;
|
||||
out->window_group = (xh->flags & XCB_ICCCM_WM_HINT_WINDOW_GROUP) ? (WNativeWindow)xh->window_group : WM_NATIVE_NONE;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
|
|
|
|||
|
|
@ -223,7 +223,26 @@ void wl_noop_cursor_set(WNativeWindow window, WMNativeCursor cursor) { (void)win
|
|||
void wl_appicon_paint_dock_dots(WAppIcon *aicon, void *wapp);
|
||||
|
||||
int wl_noop_pixmap_get_size(unsigned long drawable, unsigned int *w, unsigned int *h, unsigned int *depth)
|
||||
{ (void)drawable; *w = 0; *h = 0; *depth = 0; return 0; }
|
||||
{
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id((WNativeWindow)drawable);
|
||||
if (v) {
|
||||
if (v->xw_surface) {
|
||||
*w = v->xw_surface->width;
|
||||
*h = v->xw_surface->height;
|
||||
} else if (v->xdg_surface) {
|
||||
struct wlr_box geo = v->xdg_surface->geometry;
|
||||
*w = geo.width > 0 ? geo.width : v->xdg_surface->surface->current.width;
|
||||
*h = geo.height > 0 ? geo.height : v->xdg_surface->surface->current.height;
|
||||
} else {
|
||||
*w = 64;
|
||||
*h = 64;
|
||||
}
|
||||
*depth = 24;
|
||||
return 1;
|
||||
}
|
||||
*w = 0; *h = 0; *depth = 0;
|
||||
return 0;
|
||||
}
|
||||
void wl_noop_icon_paint_title_bg(WScreen *scr, unsigned long pixmap, int height)
|
||||
{ (void)scr; (void)pixmap; (void)height; }
|
||||
void wl_noop_icon_select_paint(WIcon *icon, int step)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/xwayland.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#include "../../menu.h"
|
||||
#include "../../balloon.h"
|
||||
#include "../../framewin.h"
|
||||
|
|
@ -79,6 +81,22 @@ wl_window_map(WNativeWindow win)
|
|||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (v && v->scene_node) {
|
||||
wlr_scene_node_set_enabled(&v->scene_node->node, true);
|
||||
/* Ensure XWayland X11 window is mapped so it composites children
|
||||
* (needed for dockapps whose content is in a child icon_window). */
|
||||
/* For XWayland dockapps: map the X11 window and reparent the
|
||||
* icon_window child into it so XWayland composites the content. */
|
||||
if (v->xw_surface && wl_state.x_display && v->xw_surface->hints &&
|
||||
(v->xw_surface->hints->flags & XCB_ICCCM_WM_HINT_STATE) &&
|
||||
v->xw_surface->hints->initial_state == 0 /* WithdrawnState */) {
|
||||
Window xwin = (Window)v->xw_surface->window_id;
|
||||
XMapWindow(wl_state.x_display, xwin);
|
||||
if (v->xw_surface->hints->flags & XCB_ICCCM_WM_HINT_ICON_WINDOW) {
|
||||
Window icon_xwin = (Window)v->xw_surface->hints->icon_window;
|
||||
XReparentWindow(wl_state.x_display, icon_xwin, xwin, 0, 0);
|
||||
XMapWindow(wl_state.x_display, icon_xwin);
|
||||
}
|
||||
XFlush(wl_state.x_display);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (v)
|
||||
|
|
|
|||
25
src/icon.c
25
src/icon.c
|
|
@ -675,7 +675,7 @@ void update_icon_pixmap(WIcon *icon)
|
|||
icon_update_pixmap(icon, icon->file_image);
|
||||
|
||||
/* If dockapp, put inside the icon */
|
||||
if (icon->icon_win != WM_NATIVE_NONE) {
|
||||
if (icon->icon_win != WM_NATIVE_NONE && !icon->file_image) {
|
||||
/* file_image is NULL, because is docked app */
|
||||
icon_update_pixmap(icon, NULL);
|
||||
set_dockapp_in_icon(icon);
|
||||
|
|
@ -766,10 +766,19 @@ static void get_rimage_icon_from_icon_win(WIcon *icon)
|
|||
{
|
||||
RImage *image;
|
||||
|
||||
/* Create the new RImage via backend (X11: parses _NET_WM_ICON via dpy;
|
||||
* Wayland: parses _NET_WM_ICON via wl_state.x_display for XWayland). */
|
||||
/* Try _NET_WM_ICON first */
|
||||
image = (RImage *)wm_backend->window_get_icon_image(icon->icon_win);
|
||||
|
||||
/* For dockapps: capture pixels from the real icon_window via XGetImage.
|
||||
* The icon_window must be mapped first. */
|
||||
if (!image && icon->owner && icon->owner->wm_hints &&
|
||||
(icon->owner->wm_hints->flags & WMH_ICON_WINDOW_HINT)) {
|
||||
WNativeWindow real_icon_win = icon->owner->wm_hints->icon_window;
|
||||
wm_backend->window_map((WNativeWindow)real_icon_win);
|
||||
image = (RImage *)wm_backend->create_rimage_from_drawable(
|
||||
icon->core->screen_ptr->rcontext, (WMDrawable)real_icon_win);
|
||||
}
|
||||
|
||||
/* Free the icon info */
|
||||
unset_icon_image(icon);
|
||||
|
||||
|
|
@ -785,9 +794,15 @@ static void set_dockapp_in_icon(WIcon *icon)
|
|||
|
||||
/* Reparent the dock application to the icon */
|
||||
|
||||
/* We need the application size to center it
|
||||
* and show in the correct position */
|
||||
/* Resize the dockapp to fill the icon tile if it's too small.
|
||||
* XWayland dockapps often have a tiny main window with content
|
||||
* drawn into a child icon_window. */
|
||||
getSize(icon->icon_win, &w, &h, &d);
|
||||
if (w < (unsigned)wPreferences.icon_size || h < (unsigned)wPreferences.icon_size) {
|
||||
w = wPreferences.icon_size;
|
||||
h = wPreferences.icon_size;
|
||||
wm_backend->window_resize((WNativeWindow)icon->icon_win, w, h);
|
||||
}
|
||||
|
||||
/* Set the background pixmap */
|
||||
wm_backend->window_set_background_pixmap((WNativeWindow)icon->core->window, (unsigned long)scr->icon_tile_pixmap);
|
||||
|
|
|
|||
Loading…
Reference in New Issue