wayland: implement appicon dock/clip clamping
Enable the full appicon drag-to-dock/clip workflow for native Wayland clients: - window.c: Set main_window = client_win for Wayland clients that lack client_leader and window_group, so wApplicationCreate runs and produces a WAppIcon. - wl_xdg.c: Call wApplicationDestroy after wUnmanageWindow on toplevel unmap, mirroring the X11 handleDestroyNotify path. Fixes appicons persisting after app close. - wl_event.c: Commit the wlroots scene in wl_event_flush so slide_windows animation renders intermediate frames. - backend.h, x11_backend.c, wl_icon.c, superfluous.c: Add create_rimage_from_drawable vtable method so MakeGhostIcon can read frame_buf pixels on Wayland for the dock shadow overlay. - wl_icon.c, wl_stubs.c: Implement wl_icon_update_pixmap with shadowed (dimmed) overlay for attracted icons. - wl_dock.c: Disable the placeholder shm_surface dock panel now that the real wmaker dock framework operates via frame_bufs.
This commit is contained in:
parent
50d0cc2c04
commit
29d183fe8f
|
|
@ -468,6 +468,13 @@ typedef struct WMBackend {
|
|||
*/
|
||||
void *(*window_get_icon_image)(WNativeWindow win);
|
||||
|
||||
/*
|
||||
* Create an RImage from a drawable (window or pixmap ID).
|
||||
* Used by MakeGhostIcon to read pixel data from an icon's frame buffer.
|
||||
* Returns a new RImage* or NULL. Caller must RReleaseImage.
|
||||
*/
|
||||
void *(*create_rimage_from_drawable)(void *rcontext, WMDrawable drawable);
|
||||
|
||||
/*
|
||||
* Read the _WINDOWMAKER_MENU text property from win.
|
||||
* On success stores an XFreeStringList-allocated string array in *list_out,
|
||||
|
|
|
|||
|
|
@ -102,6 +102,10 @@ wm_dock_render(struct wm_shm_surface *s, int icon_sz, int n_slots)
|
|||
void
|
||||
wm_dock_create(WScreen *scr)
|
||||
{
|
||||
/* Disabled: the real wmaker dock framework handles icons via frame_bufs.
|
||||
* This shm_surface panel was a placeholder. */
|
||||
(void)scr;
|
||||
return;
|
||||
if (!wl_state.scene || !wl_state.output)
|
||||
return;
|
||||
|
||||
|
|
@ -273,6 +277,8 @@ wm_dock_refresh(void)
|
|||
void
|
||||
wm_dock_app_add(struct wl_toplevel_view *v)
|
||||
{
|
||||
(void)v;
|
||||
return; /* Disabled: real dock handles icons via frame_bufs */
|
||||
if (!wl_state.dock_surface) return;
|
||||
if (wl_state.dock_app_count >= WM_DOCK_MAX_APPS) return;
|
||||
|
||||
|
|
@ -298,6 +304,8 @@ wm_dock_app_add(struct wl_toplevel_view *v)
|
|||
void
|
||||
wm_dock_app_remove(WNativeWindow id)
|
||||
{
|
||||
(void)id;
|
||||
return; /* Disabled: real dock handles icons via frame_bufs */
|
||||
if (!wl_state.dock_surface) return;
|
||||
|
||||
for (int i = 0; i < wl_state.dock_app_count; i++) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "../../screen.h"
|
||||
#include "wl_types.h"
|
||||
|
||||
|
|
@ -8,6 +10,9 @@
|
|||
void wl_event_flush(void)
|
||||
{
|
||||
wl_xdisplay_flush();
|
||||
/* Commit the scene so intermediate animation frames are visible */
|
||||
if (wl_state.scene_output && wl_state.allocator)
|
||||
wlr_scene_output_commit(wl_state.scene_output, NULL);
|
||||
}
|
||||
void wl_event_flush_expose(void) {}
|
||||
void wl_event_sync(int discard)
|
||||
|
|
|
|||
|
|
@ -280,3 +280,80 @@ 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 */
|
||||
void *
|
||||
wl_create_rimage_from_drawable(void *rcontext, WMDrawable drawable)
|
||||
{
|
||||
(void)rcontext;
|
||||
if (!drawable)
|
||||
return NULL;
|
||||
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)drawable);
|
||||
if (!fb || !fb->image)
|
||||
return NULL;
|
||||
|
||||
int w = pixman_image_get_width(fb->image);
|
||||
int h = pixman_image_get_height(fb->image);
|
||||
if (w <= 0 || h <= 0)
|
||||
return NULL;
|
||||
|
||||
RImage *img = RCreateImage(w, h, 1);
|
||||
if (!img)
|
||||
return NULL;
|
||||
|
||||
uint32_t *src = (uint32_t *)pixman_image_get_data(fb->image);
|
||||
int stride = pixman_image_get_stride(fb->image) / 4;
|
||||
unsigned char *dst = img->data;
|
||||
|
||||
for (int row = 0; row < h; row++) {
|
||||
for (int col = 0; col < w; col++) {
|
||||
uint32_t px = src[row * stride + col];
|
||||
*dst++ = (px >> 16) & 0xFF; /* R */
|
||||
*dst++ = (px >> 8) & 0xFF; /* G */
|
||||
*dst++ = px & 0xFF; /* B */
|
||||
*dst++ = (px >> 24) & 0xFF; /* A */
|
||||
}
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
/* Re-render icon pixmap; applies shadowed (dimmed) overlay for attracted icons */
|
||||
void
|
||||
wl_icon_update_pixmap(WIcon *icon)
|
||||
{
|
||||
if (!icon || !icon->core)
|
||||
return;
|
||||
|
||||
/* Find the owning appicon and repaint it */
|
||||
WAppIcon *aicon = (WAppIcon *)icon->core->descriptor.parent;
|
||||
if (aicon && icon->core->descriptor.parent_type == WCLASS_APPICON)
|
||||
wl_appicon_paint(aicon);
|
||||
else if (aicon && icon->core->descriptor.parent_type == WCLASS_DOCK_ICON)
|
||||
wl_appicon_paint(aicon);
|
||||
else
|
||||
wl_icon_paint(icon);
|
||||
|
||||
/* Apply shadowed overlay (semi-transparent dark wash) for attracted icons */
|
||||
if (icon->shadowed) {
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)icon->core->window);
|
||||
if (fb && fb->image) {
|
||||
int w = pixman_image_get_width(fb->image);
|
||||
int h = pixman_image_get_height(fb->image);
|
||||
uint32_t *px = (uint32_t *)pixman_image_get_data(fb->image);
|
||||
int stride = pixman_image_get_stride(fb->image) / 4;
|
||||
for (int row = 0; row < h; row++) {
|
||||
for (int col = 0; col < w; col++) {
|
||||
uint32_t p = px[row * stride + col];
|
||||
uint32_t a = (p >> 24) & 0xFF;
|
||||
uint32_t r = ((p >> 16) & 0xFF) / 2;
|
||||
uint32_t g = ((p >> 8) & 0xFF) / 2;
|
||||
uint32_t b = (p & 0xFF) / 2;
|
||||
px[row * stride + col] = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
}
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ void wl_netwm_update_opacity(WWindow *wwin);
|
|||
void wl_icon_paint(WIcon *icon);
|
||||
void wl_appicon_show(WApplication *wapp);
|
||||
void wl_appicon_paint(WAppIcon *aicon);
|
||||
void *wl_create_rimage_from_drawable(void *rcontext, WMDrawable drawable);
|
||||
void wl_icon_update_pixmap(WIcon *icon);
|
||||
void wl_client_set_state(WWindow *wwin, int state, WNativeWindow icon_win);
|
||||
void wl_client_set_maximized(WNativeWindow win, int maximized);
|
||||
void wl_client_send_protocol(WWindow *wwin, unsigned long protocol, unsigned long timestamp);
|
||||
|
|
@ -325,6 +327,7 @@ const WMBackend wl_backend = {
|
|||
.window_get_icon_name = wl_window_get_icon_name,
|
||||
.screen_get_head_usable_area = wl_noop_screen_get_head_usable_area,
|
||||
.window_get_icon_image = wl_window_get_icon_image,
|
||||
.create_rimage_from_drawable = wl_create_rimage_from_drawable,
|
||||
.prop_get_wmaker_menu = wl_prop_get_wmaker_menu,
|
||||
.prop_get_transient_for = wl_prop_get_transient_for,
|
||||
.prop_has_wmaker_menu = wl_prop_has_wmaker_menu,
|
||||
|
|
@ -449,7 +452,7 @@ const WMBackend wl_backend = {
|
|||
.get_text_selection = wl_noop_get_text_selection,
|
||||
.get_shortcut_string = wl_noop_get_shortcut_string,
|
||||
.get_command_for_window = wl_get_command_for_window,
|
||||
.icon_update_pixmap = wl_noop_icon_update_pixmap,
|
||||
.icon_update_pixmap = wl_icon_update_pixmap,
|
||||
.icon_paint = wl_icon_paint,
|
||||
.appicon_show = wl_appicon_show,
|
||||
.appicon_paint = wl_appicon_paint,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "../../actions.h"
|
||||
#include "../../xinerama.h"
|
||||
#include "../../framewin.h"
|
||||
#include "../../application.h"
|
||||
#include <WINGs/WINGsP.h>
|
||||
|
||||
/* Forward declarations for functions defined in other wl_*.c files */
|
||||
|
|
@ -393,7 +394,16 @@ handle_toplevel_unmap(struct wl_listener *listener, void *data)
|
|||
WObjDescriptor *desc = wm_backend->context_find(view->id, WM_CTX_CLIENT_WIN);
|
||||
if (desc && desc->parent_type == WCLASS_WINDOW) {
|
||||
WWindow *wwin = (WWindow *)desc->parent;
|
||||
WNativeWindow main_win = wwin->main_window;
|
||||
wUnmanageWindow(wwin, False, True);
|
||||
/* Destroy the WApplication (and its appicon) if this was the
|
||||
* main window. Mirrors handleDestroyNotify in event.c. */
|
||||
WApplication *app = wApplicationOf(main_win);
|
||||
if (app) {
|
||||
if (main_win == app->main_window)
|
||||
app->refcount = 0;
|
||||
wApplicationDestroy(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1356,6 +1356,12 @@ x11_window_get_icon_image(WNativeWindow win)
|
|||
return get_window_image_from_x11(dpy, WNW_TO_XID(win));
|
||||
}
|
||||
|
||||
static void *
|
||||
x11_create_rimage_from_drawable(void *rcontext, WMDrawable drawable)
|
||||
{
|
||||
return RCreateImageFromDrawable((RContext *)rcontext, (Drawable)drawable, None);
|
||||
}
|
||||
|
||||
static int
|
||||
x11_prop_get_wmaker_menu(WNativeWindow win, char ***list_out, int *count_out)
|
||||
{
|
||||
|
|
@ -4795,6 +4801,7 @@ const WMBackend x11_backend = {
|
|||
.window_get_icon_name = x11_window_get_icon_name,
|
||||
.screen_get_head_usable_area = x11_screen_get_head_usable_area,
|
||||
.window_get_icon_image = x11_window_get_icon_image,
|
||||
.create_rimage_from_drawable = x11_create_rimage_from_drawable,
|
||||
.prop_get_wmaker_menu = x11_prop_get_wmaker_menu,
|
||||
.monitors_query = x11_monitors_query,
|
||||
.monitors_select_events = x11_monitors_select_events,
|
||||
|
|
|
|||
|
|
@ -61,9 +61,12 @@ WMNativePixmap MakeGhostIcon(WScreen * scr, WMDrawable drawable)
|
|||
if (!drawable)
|
||||
return WM_NATIVE_NONE;
|
||||
|
||||
back = RCreateImageFromDrawable(scr->rcontext, drawable, WM_NATIVE_NONE);
|
||||
if (!back)
|
||||
back = (RImage *)wm_backend->create_rimage_from_drawable(scr->rcontext, drawable);
|
||||
if (!back) {
|
||||
wwarning("MakeGhostIcon: create_rimage_from_drawable failed for drawable=0x%lx", (unsigned long)drawable);
|
||||
return WM_NATIVE_NONE;
|
||||
}
|
||||
wwarning("MakeGhostIcon: got RImage %dx%d from drawable=0x%lx", back->width, back->height, (unsigned long)drawable);
|
||||
|
||||
color.red = 0xff;
|
||||
color.green = 0xff;
|
||||
|
|
@ -71,7 +74,12 @@ WMNativePixmap MakeGhostIcon(WScreen * scr, WMDrawable drawable)
|
|||
color.alpha = 200;
|
||||
|
||||
RClearImage(back, &color);
|
||||
RConvertImage(scr->rcontext, back, &pixmap);
|
||||
if (!RConvertImage(scr->rcontext, back, &pixmap)) {
|
||||
wwarning("MakeGhostIcon: RConvertImage failed");
|
||||
RReleaseImage(back);
|
||||
return WM_NATIVE_NONE;
|
||||
}
|
||||
wwarning("MakeGhostIcon: converted to pixmap=0x%lx", (unsigned long)pixmap);
|
||||
|
||||
RReleaseImage(back);
|
||||
|
||||
|
|
|
|||
|
|
@ -749,6 +749,15 @@ WWindow *wManageWindow(WScreen *scr, WNativeWindow window)
|
|||
if (WFLAGP(wwin, emulate_appicon))
|
||||
wwin->main_window = wwin->client_win;
|
||||
|
||||
/* Wayland native clients have no client_leader or window_group.
|
||||
* Treat each non-transient window as its own app leader so that
|
||||
* wApplicationCreate runs and an appicon is produced. */
|
||||
if (wwin->main_window == WM_NATIVE_NONE
|
||||
&& wwin->transient_for == WM_NATIVE_NONE
|
||||
&& wwin->client_leader == WM_NATIVE_NONE
|
||||
&& wwin->group_id == WM_NATIVE_NONE)
|
||||
wwin->main_window = wwin->client_win;
|
||||
|
||||
fixLeaderProperties(wwin);
|
||||
|
||||
wwin->orig_main_window = wwin->main_window;
|
||||
|
|
|
|||
Loading…
Reference in New Issue