Implement popup-style toplevels for menu editor on Wayland
The WPrefs menu editor creates standalone draggable windows for each menu item via W_CreateTopView. On X11 these are override-redirect windows. On Wayland they were becoming framed XDG toplevels with taskbar entries, cluttering the desktop with phantom 'WINGs...' tabs. Implementation: 1. New W_View flags.popup field, set by editmenu's standalone mode 2. wclient_wl: when realizing a popup view, set xdg_toplevel app_id to 'wings-popup' as a hint to the compositor 3. wmaker compositor: detect 'wings-popup' app_id in toplevel_map, set borderless + skip-taskbar + skip-switchpanel flags, then call wWindowConfigureBorders to rebuild the frame without decorations 4. New W_EventBackend->window_begin_move vtable method: - X11: returns False (caller runs manual drag loop) - Wayland: calls xdg_toplevel_move, returns True (compositor drives drag) 5. editmenu's dragMenu calls window_begin_move first; on Wayland the compositor handles the entire drag, so the manual loop is skipped
This commit is contained in:
parent
e01dedb833
commit
04e6b348b2
|
|
@ -495,6 +495,10 @@ typedef struct W_EventBackend {
|
||||||
int *x, int *y,
|
int *x, int *y,
|
||||||
unsigned int *width, unsigned int *height);
|
unsigned int *width, unsigned int *height);
|
||||||
void (*move_window)(void *ectx, WNativeWindow window, int x, int y);
|
void (*move_window)(void *ectx, WNativeWindow window, int x, int y);
|
||||||
|
/* Begin interactive window move (Wayland: xdg_toplevel_move).
|
||||||
|
* Returns True if the backend will handle the move, False if the
|
||||||
|
* caller should run its own drag loop (X11). */
|
||||||
|
Bool (*window_begin_move)(void *ectx, WNativeWindow window);
|
||||||
WNativeWindow (*translate_coordinates)(void *ectx,
|
WNativeWindow (*translate_coordinates)(void *ectx,
|
||||||
WNativeWindow src, WNativeWindow dst,
|
WNativeWindow src, WNativeWindow dst,
|
||||||
int src_x, int src_y,
|
int src_x, int src_y,
|
||||||
|
|
@ -1024,6 +1028,7 @@ struct W_View {
|
||||||
unsigned int root:1; /* is the root window */
|
unsigned int root:1; /* is the root window */
|
||||||
unsigned int mapWhenRealized:1; /* map the view when it's realized */
|
unsigned int mapWhenRealized:1; /* map the view when it's realized */
|
||||||
unsigned int alreadyDead:1; /* view was freed */
|
unsigned int alreadyDead:1; /* view was freed */
|
||||||
|
unsigned int popup:1; /* popup-style toplevel (no frame, no taskbar) */
|
||||||
|
|
||||||
unsigned int dontCompressMotion:1; /* motion notify event compress */
|
unsigned int dontCompressMotion:1; /* motion notify event compress */
|
||||||
unsigned int notifySizeChanged:1;
|
unsigned int notifySizeChanged:1;
|
||||||
|
|
|
||||||
|
|
@ -450,8 +450,13 @@ wl_client_toplevel_realize(struct W_View *view, int width, int height)
|
||||||
/* Default app_id; the application can override via xdg_toplevel_set_app_id.
|
/* Default app_id; the application can override via xdg_toplevel_set_app_id.
|
||||||
* WPrefs and friends ought to call WMSetApplicationIconImage / set_title;
|
* WPrefs and friends ought to call WMSetApplicationIconImage / set_title;
|
||||||
* we'll plumb that next. */
|
* we'll plumb that next. */
|
||||||
xdg_toplevel_set_app_id(top->xdg_toplevel, "WINGs");
|
if (view->flags.popup) {
|
||||||
xdg_toplevel_set_title(top->xdg_toplevel, "WINGs Application");
|
xdg_toplevel_set_app_id(top->xdg_toplevel, "wings-popup");
|
||||||
|
xdg_toplevel_set_title(top->xdg_toplevel, "");
|
||||||
|
} else {
|
||||||
|
xdg_toplevel_set_app_id(top->xdg_toplevel, "WINGs");
|
||||||
|
xdg_toplevel_set_title(top->xdg_toplevel, "WINGs Application");
|
||||||
|
}
|
||||||
|
|
||||||
/* Initial commit with no buffer so the compositor sends the first
|
/* Initial commit with no buffer so the compositor sends the first
|
||||||
* configure. We attach a real buffer in the configure handler. */
|
* configure. We attach a real buffer in the configure handler. */
|
||||||
|
|
@ -510,6 +515,25 @@ W_WLClientSetMinMaxSize(W_View *view)
|
||||||
wl_surface_commit(top->surface);
|
wl_surface_commit(top->surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bool
|
||||||
|
W_WLClientBeginMove(WNativeWindow window)
|
||||||
|
{
|
||||||
|
extern uint32_t wlc_ptr_button_serial;
|
||||||
|
extern W_View *wlc_ptr_grab;
|
||||||
|
extern unsigned int wlc_ptr_button_state;
|
||||||
|
WLClientCtx *ctx = g_wlclient_ctx;
|
||||||
|
WLClientToplevel *top = wlc_top_find(window);
|
||||||
|
if (!ctx || !ctx->seat || !top || !top->xdg_toplevel) return False;
|
||||||
|
if (wlc_ptr_button_serial == 0) return False;
|
||||||
|
xdg_toplevel_move(top->xdg_toplevel, ctx->seat, wlc_ptr_button_serial);
|
||||||
|
/* Release implicit grab — the compositor now owns the input until
|
||||||
|
* the user releases the button. */
|
||||||
|
wlc_ptr_grab = NULL;
|
||||||
|
/* Clear pressed state so widgets don't think the button is still down */
|
||||||
|
wlc_ptr_button_state = 0;
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
/* Input: wl_pointer / wl_keyboard listeners */
|
/* Input: wl_pointer / wl_keyboard listeners */
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
@ -540,11 +564,12 @@ wlc_xkb_mod_mask(struct xkb_state *state)
|
||||||
/* Pointer state */
|
/* Pointer state */
|
||||||
static double wlc_ptr_x, wlc_ptr_y;
|
static double wlc_ptr_x, wlc_ptr_y;
|
||||||
static uint32_t wlc_ptr_focus_serial;
|
static uint32_t wlc_ptr_focus_serial;
|
||||||
|
uint32_t wlc_ptr_button_serial; /* serial of most recent button press */
|
||||||
static WLClientToplevel *wlc_ptr_focused;
|
static WLClientToplevel *wlc_ptr_focused;
|
||||||
static unsigned int wlc_ptr_button_state;
|
unsigned int wlc_ptr_button_state;
|
||||||
static unsigned int wlc_ptr_mods;
|
static unsigned int wlc_ptr_mods;
|
||||||
static W_View *wlc_ptr_child_focus;
|
static W_View *wlc_ptr_child_focus;
|
||||||
static W_View *wlc_ptr_grab; /* implicit grab: deliver events here while button held */
|
W_View *wlc_ptr_grab; /* implicit grab: deliver events here while button held */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hit-test: find the deepest child view at (x,y) relative to the toplevel,
|
* Hit-test: find the deepest child view at (x,y) relative to the toplevel,
|
||||||
|
|
@ -706,9 +731,11 @@ static void
|
||||||
pointer_handle_button(void *data, struct wl_pointer *p, uint32_t serial,
|
pointer_handle_button(void *data, struct wl_pointer *p, uint32_t serial,
|
||||||
uint32_t time, uint32_t button, uint32_t state)
|
uint32_t time, uint32_t button, uint32_t state)
|
||||||
{
|
{
|
||||||
(void)p; (void)serial;
|
(void)p;
|
||||||
WLClientCtx *ctx = data;
|
WLClientCtx *ctx = data;
|
||||||
if (!wlc_ptr_focused) return;
|
if (!wlc_ptr_focused) return;
|
||||||
|
if (state == WL_POINTER_BUTTON_STATE_PRESSED)
|
||||||
|
wlc_ptr_button_serial = serial;
|
||||||
|
|
||||||
/* Linux input event codes -> X-style button numbers. */
|
/* Linux input event codes -> X-style button numbers. */
|
||||||
unsigned int wmb;
|
unsigned int wmb;
|
||||||
|
|
|
||||||
|
|
@ -219,6 +219,16 @@ static Bool wl_get_window_geometry(void *ectx, WNativeWindow w,
|
||||||
static void wl_move_window(void *ectx, WNativeWindow w, int x, int y)
|
static void wl_move_window(void *ectx, WNativeWindow w, int x, int y)
|
||||||
{ (void)ectx; (void)w; (void)x; (void)y; }
|
{ (void)ectx; (void)w; (void)x; (void)y; }
|
||||||
|
|
||||||
|
/* Implemented in wclient_wl.c — calls xdg_toplevel_move on the client
|
||||||
|
* connection so the compositor handles the drag. */
|
||||||
|
extern Bool W_WLClientBeginMove(WNativeWindow window);
|
||||||
|
|
||||||
|
static Bool wl_window_begin_move(void *ectx, WNativeWindow window)
|
||||||
|
{
|
||||||
|
(void)ectx;
|
||||||
|
return W_WLClientBeginMove(window);
|
||||||
|
}
|
||||||
|
|
||||||
static WNativeWindow wl_translate_coordinates(void *ectx,
|
static WNativeWindow wl_translate_coordinates(void *ectx,
|
||||||
WNativeWindow src, WNativeWindow dst, int sx, int sy, int *dx, int *dy)
|
WNativeWindow src, WNativeWindow dst, int sx, int sy, int *dx, int *dy)
|
||||||
{ (void)ectx; (void)src; (void)dst; (void)sx; (void)sy;
|
{ (void)ectx; (void)src; (void)dst; (void)sx; (void)sy;
|
||||||
|
|
@ -317,6 +327,7 @@ const W_EventBackend W_EventBackendWL = {
|
||||||
.query_pointer = wl_query_pointer,
|
.query_pointer = wl_query_pointer,
|
||||||
.get_window_geometry = wl_get_window_geometry,
|
.get_window_geometry = wl_get_window_geometry,
|
||||||
.move_window = wl_move_window,
|
.move_window = wl_move_window,
|
||||||
|
.window_begin_move = wl_window_begin_move,
|
||||||
.translate_coordinates = wl_translate_coordinates,
|
.translate_coordinates = wl_translate_coordinates,
|
||||||
.get_root_window = wl_get_root_window,
|
.get_root_window = wl_get_root_window,
|
||||||
.query_tree = wl_query_tree,
|
.query_tree = wl_query_tree,
|
||||||
|
|
|
||||||
|
|
@ -435,6 +435,14 @@ x11_move_window(void *ectx, WNativeWindow window, int x, int y)
|
||||||
XMoveWindow(ctx->dpy, (Window)window, x, y);
|
XMoveWindow(ctx->dpy, (Window)window, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
x11_window_begin_move(void *ectx, WNativeWindow window)
|
||||||
|
{
|
||||||
|
(void)ectx; (void)window;
|
||||||
|
/* X11 uses manual drag loop with grab_pointer; no backend assist. */
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
static WNativeWindow
|
static WNativeWindow
|
||||||
x11_translate_coordinates(void *ectx, WNativeWindow src, WNativeWindow dst,
|
x11_translate_coordinates(void *ectx, WNativeWindow src, WNativeWindow dst,
|
||||||
int src_x, int src_y, int *dst_x, int *dst_y)
|
int src_x, int src_y, int *dst_x, int *dst_y)
|
||||||
|
|
@ -759,6 +767,7 @@ const W_EventBackend W_EventBackendX11 = {
|
||||||
.query_pointer = x11_query_pointer,
|
.query_pointer = x11_query_pointer,
|
||||||
.get_window_geometry = x11_get_window_geometry,
|
.get_window_geometry = x11_get_window_geometry,
|
||||||
.move_window = x11_move_window,
|
.move_window = x11_move_window,
|
||||||
|
.window_begin_move = x11_window_begin_move,
|
||||||
.translate_coordinates = x11_translate_coordinates,
|
.translate_coordinates = x11_translate_coordinates,
|
||||||
.get_root_window = x11_get_root_window,
|
.get_root_window = x11_get_root_window,
|
||||||
.query_tree = x11_query_tree,
|
.query_tree = x11_query_tree,
|
||||||
|
|
|
||||||
|
|
@ -383,6 +383,8 @@ static WEditMenu *makeEditMenu(WMScreen * scr, WMWidget * parent, const char *ti
|
||||||
} else {
|
} else {
|
||||||
mPtr->view = W_CreateTopView(scr);
|
mPtr->view = W_CreateTopView(scr);
|
||||||
mPtr->flags.standalone = 1;
|
mPtr->flags.standalone = 1;
|
||||||
|
if (mPtr->view)
|
||||||
|
mPtr->view->flags.popup = 1;
|
||||||
}
|
}
|
||||||
if (!mPtr->view) {
|
if (!mPtr->view) {
|
||||||
wfree(mPtr);
|
wfree(mPtr);
|
||||||
|
|
@ -1050,6 +1052,17 @@ static void dragMenu(WEditMenu * menu)
|
||||||
unsigned blau;
|
unsigned blau;
|
||||||
WNativeWindow blaw;
|
WNativeWindow blaw;
|
||||||
|
|
||||||
|
if (menu->parent)
|
||||||
|
WTearOffEditMenu(menu->parent, menu);
|
||||||
|
|
||||||
|
/* Wayland: ask compositor to drive the move, then return. X11:
|
||||||
|
* fall through to manual drag loop. */
|
||||||
|
if (scr->eventBackend->window_begin_move
|
||||||
|
&& scr->eventBackend->window_begin_move(scr->eventBackendCtx,
|
||||||
|
W_VIEW_DRAWABLE(menu->view))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
scr->eventBackend->get_window_geometry(scr->eventBackendCtx,
|
scr->eventBackend->get_window_geometry(scr->eventBackendCtx,
|
||||||
W_VIEW_DRAWABLE(menu->view), &dx, &dy, &blau, &blau);
|
W_VIEW_DRAWABLE(menu->view), &dx, &dy, &blau, &blau);
|
||||||
|
|
||||||
|
|
@ -1060,9 +1073,6 @@ static void dragMenu(WEditMenu * menu)
|
||||||
|
|
||||||
scr->eventBackend->grab_pointer(scr->eventBackendCtx, scr->rootWin, scr->defaultCursor);
|
scr->eventBackend->grab_pointer(scr->eventBackendCtx, scr->rootWin, scr->defaultCursor);
|
||||||
|
|
||||||
if (menu->parent)
|
|
||||||
WTearOffEditMenu(menu->parent, menu);
|
|
||||||
|
|
||||||
while (!done) {
|
while (!done) {
|
||||||
WMNextEvent(scr, &ev);
|
WMNextEvent(scr, &ev);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1138,12 +1138,34 @@ handle_toplevel_map(struct wl_listener *listener, void *data)
|
||||||
view->xdg_surface->toplevel->app_id ? view->xdg_surface->toplevel->app_id : "(none)",
|
view->xdg_surface->toplevel->app_id ? view->xdg_surface->toplevel->app_id : "(none)",
|
||||||
view->xdg_surface->toplevel->title ? view->xdg_surface->toplevel->title : "(none)");
|
view->xdg_surface->toplevel->title ? view->xdg_surface->toplevel->title : "(none)");
|
||||||
|
|
||||||
|
/* Detect popup-style WINGs windows (menu editor items, etc.) — these
|
||||||
|
* need borderless presentation, no taskbar entry, and free positioning. */
|
||||||
|
const char *app_id_check = view->xdg_surface->toplevel->app_id;
|
||||||
|
int is_popup = (app_id_check && strcmp(app_id_check, "wings-popup") == 0);
|
||||||
|
|
||||||
/* Phase 39/41: register the surface as a managed window. */
|
/* Phase 39/41: register the surface as a managed window. */
|
||||||
{
|
{
|
||||||
WScreen *scr = wScreenWithNumber(0);
|
WScreen *scr = wScreenWithNumber(0);
|
||||||
if (scr) {
|
if (scr) {
|
||||||
WWindow *wwin = wManageWindow(scr, view->id);
|
WWindow *wwin = wManageWindow(scr, view->id);
|
||||||
if (wwin) {
|
if (wwin) {
|
||||||
|
if (is_popup) {
|
||||||
|
/* Set borderless + skip-taskbar attributes */
|
||||||
|
wwin->client_flags.no_border = 1;
|
||||||
|
wwin->client_flags.no_titlebar = 1;
|
||||||
|
wwin->client_flags.no_closable = 1;
|
||||||
|
wwin->client_flags.no_miniaturizable = 1;
|
||||||
|
wwin->client_flags.no_resizable = 1;
|
||||||
|
wwin->client_flags.no_close_button = 1;
|
||||||
|
wwin->client_flags.no_miniaturize_button = 1;
|
||||||
|
wwin->client_flags.no_resizebar = 1;
|
||||||
|
wwin->client_flags.skip_window_list = 1;
|
||||||
|
wwin->client_flags.skip_switchpanel = 1;
|
||||||
|
wwin->user_flags = wwin->client_flags;
|
||||||
|
/* Rebuild frame without decorations */
|
||||||
|
extern void wWindowConfigureBorders(WWindow *wwin);
|
||||||
|
wWindowConfigureBorders(wwin);
|
||||||
|
}
|
||||||
int pid = wl_client_get_pid(view->id);
|
int pid = wl_client_get_pid(view->id);
|
||||||
/* Phase 62: focus delivered by wManageWindow via wSetFocusTo
|
/* Phase 62: focus delivered by wManageWindow via wSetFocusTo
|
||||||
* (auto_focus=1 set in wl_screen_create_internals); the
|
* (auto_focus=1 set in wl_screen_create_internals); the
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue