wayland: Phase 39 — wire toplevel map to wManageWindow
Guard all dpy==NULL crash sites reached from wManageWindow: - wNETWMGetPidForWindow (wmspec.c) — XGetWindowProperty with NULL dpy - wNETWMCheckClientHints (wmspec.c) — XGetWindowProperty - wNETWMCheckInitialClientState (wmspec.c) — XChangeProperty chain - getMWMHints (motif.c) — XInternAtom before NULL dpy check - wClientSetState (client.c) — XChangeProperty - wColormapInstallForWindow (colormap.c) — XGetWindowAttributes - wWindowSetKeyGrabs (window.c) — frame->core->window dereference Wire handle_toplevel_map → wManageWindow(scr, view->id) so mapped XDG toplevels appear in scr->focused_window. Log success via "wl_backend: wManageWindow succeeded id=0x%lx". Smoke test: add Phase 39 check — grep "wManageWindow succeeded". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
74a43f0180
commit
ca09635129
|
|
@ -15,6 +15,8 @@
|
|||
* sent on new toplevel so clients complete their first frame.
|
||||
* Phase 38: per-toplevel view struct with map/unmap/destroy lifecycle;
|
||||
* synthetic WNativeWindow IDs; context_save/find/delete implemented.
|
||||
* Phase 39: handle_toplevel_map wires XDG toplevel map to wManageWindow so
|
||||
* Wayland surfaces appear in scr->focused_window list.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
@ -143,8 +145,15 @@ 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->title ? view->xdg_surface->toplevel->title : "(none)");
|
||||
|
||||
/* TODO Phase 39: call wManageWindow(scr, view->id) once context
|
||||
* store can resolve the synthetic ID to this view. */
|
||||
/* Phase 39: register the surface as a managed window. */
|
||||
{
|
||||
WScreen *scr = wScreenWithNumber(0);
|
||||
if (scr) {
|
||||
WWindow *wwin = wManageWindow(scr, view->id);
|
||||
if (wwin)
|
||||
wwarning("wl_backend: wManageWindow succeeded id=0x%lx", view->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -87,6 +87,9 @@ void wClientSetState(WWindow * wwin, int state, Window icon_win)
|
|||
|
||||
wwin->state = state;
|
||||
|
||||
if (!dpy)
|
||||
return; /* Wayland: no X11 WM_STATE property */
|
||||
|
||||
data[0] = (unsigned long)state;
|
||||
data[1] = (unsigned long)icon_win;
|
||||
|
||||
|
|
@ -720,6 +723,8 @@ wClientGetNormalHints(WWindow * wwin, WClientAttributes * wattribs, int geometry
|
|||
void GetColormapWindows(WWindow * wwin)
|
||||
{
|
||||
#ifndef NO_CRASHES
|
||||
if (!dpy)
|
||||
return; /* Wayland: no X11 colormaps */
|
||||
if (wwin->cmap_windows) {
|
||||
XFree(wwin->cmap_windows);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ void wColormapInstallForWindow(WScreen * scr, WWindow * wwin)
|
|||
int done = 0;
|
||||
Window xwin = None;
|
||||
|
||||
if (!dpy)
|
||||
return; /* Wayland: no X11 colormaps */
|
||||
|
||||
if (wwin) {
|
||||
xwin = wwin->client_win;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -162,6 +162,9 @@ static int getMWMHints(Window window, MWMHints *mwmhints)
|
|||
unsigned long *data;
|
||||
int count;
|
||||
|
||||
if (!dpy)
|
||||
return 0; /* Wayland: no X11 Motif hints */
|
||||
|
||||
if (!_XA_MOTIF_WM_HINTS)
|
||||
_XA_MOTIF_WM_HINTS = XInternAtom(dpy, "_MOTIF_WM_HINTS", False);
|
||||
|
||||
|
|
|
|||
187
src/window.c
187
src/window.c
|
|
@ -1082,94 +1082,104 @@ WWindow *wManageWindow(WScreen *scr, WNativeWindow window)
|
|||
wwin->flags.omnipresent ^= 1;
|
||||
}
|
||||
|
||||
/* Create frame, borders and do reparenting */
|
||||
foo = WFF_LEFT_BUTTON | WFF_RIGHT_BUTTON;
|
||||
/* Create frame, borders and do reparenting (X11 only) */
|
||||
if (dpy) {
|
||||
foo = WFF_LEFT_BUTTON | WFF_RIGHT_BUTTON;
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
if (wPreferences.modelock)
|
||||
foo |= WFF_LANGUAGE_BUTTON;
|
||||
if (wPreferences.modelock)
|
||||
foo |= WFF_LANGUAGE_BUTTON;
|
||||
#endif
|
||||
if (HAS_TITLEBAR(wwin))
|
||||
foo |= WFF_TITLEBAR;
|
||||
if (HAS_TITLEBAR(wwin))
|
||||
foo |= WFF_TITLEBAR;
|
||||
|
||||
if (HAS_RESIZEBAR(wwin))
|
||||
foo |= WFF_RESIZEBAR;
|
||||
if (HAS_RESIZEBAR(wwin))
|
||||
foo |= WFF_RESIZEBAR;
|
||||
|
||||
if (HAS_BORDER(wwin))
|
||||
foo |= WFF_BORDER;
|
||||
if (HAS_BORDER(wwin))
|
||||
foo |= WFF_BORDER;
|
||||
|
||||
wwin->frame = wFrameWindowCreate(scr, window_level,
|
||||
x, y, width, height,
|
||||
&wPreferences.window_title_clearance,
|
||||
&wPreferences.window_title_min_height,
|
||||
&wPreferences.window_title_max_height,
|
||||
foo,
|
||||
scr->window_title_texture,
|
||||
scr->resizebar_texture, scr->window_title_color, &scr->title_font,
|
||||
wvisual.depth, wvisual.visual, (Colormap)wvisual.colormap);
|
||||
wwin->frame = wFrameWindowCreate(scr, window_level,
|
||||
x, y, width, height,
|
||||
&wPreferences.window_title_clearance,
|
||||
&wPreferences.window_title_min_height,
|
||||
&wPreferences.window_title_max_height,
|
||||
foo,
|
||||
scr->window_title_texture,
|
||||
scr->resizebar_texture, scr->window_title_color, &scr->title_font,
|
||||
wvisual.depth, wvisual.visual, (Colormap)wvisual.colormap);
|
||||
|
||||
wwin->frame->flags.is_client_window_frame = 1;
|
||||
wwin->frame->flags.justification = wPreferences.title_justification;
|
||||
wwin->frame->flags.is_client_window_frame = 1;
|
||||
wwin->frame->flags.justification = wPreferences.title_justification;
|
||||
|
||||
wNETWMCheckInitialFrameState(wwin);
|
||||
wNETWMCheckInitialFrameState(wwin);
|
||||
|
||||
/* setup button images */
|
||||
wWindowUpdateButtonImages(wwin);
|
||||
/* setup button images */
|
||||
wWindowUpdateButtonImages(wwin);
|
||||
|
||||
/* hide unused buttons */
|
||||
foo = 0;
|
||||
if (WFLAGP(wwin, no_close_button))
|
||||
foo |= WFF_RIGHT_BUTTON;
|
||||
/* hide unused buttons */
|
||||
foo = 0;
|
||||
if (WFLAGP(wwin, no_close_button))
|
||||
foo |= WFF_RIGHT_BUTTON;
|
||||
|
||||
if (WFLAGP(wwin, no_miniaturize_button))
|
||||
foo |= WFF_LEFT_BUTTON;
|
||||
if (WFLAGP(wwin, no_miniaturize_button))
|
||||
foo |= WFF_LEFT_BUTTON;
|
||||
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
if (WFLAGP(wwin, no_language_button) || WFLAGP(wwin, no_focusable))
|
||||
foo |= WFF_LANGUAGE_BUTTON;
|
||||
if (WFLAGP(wwin, no_language_button) || WFLAGP(wwin, no_focusable))
|
||||
foo |= WFF_LANGUAGE_BUTTON;
|
||||
#endif
|
||||
if (foo != 0)
|
||||
wFrameWindowHideButton(wwin->frame, foo);
|
||||
if (foo != 0)
|
||||
wFrameWindowHideButton(wwin->frame, foo);
|
||||
|
||||
wwin->frame->child = wwin;
|
||||
wwin->frame->workspace = workspace;
|
||||
wwin->frame->on_click_left = windowIconifyClick;
|
||||
wwin->frame->child = wwin;
|
||||
wwin->frame->workspace = workspace;
|
||||
wwin->frame->on_click_left = windowIconifyClick;
|
||||
|
||||
#ifdef XKB_BUTTON_HINT
|
||||
if (wPreferences.modelock)
|
||||
wwin->frame->on_click_language = windowLanguageClick;
|
||||
if (wPreferences.modelock)
|
||||
wwin->frame->on_click_language = windowLanguageClick;
|
||||
#endif
|
||||
|
||||
wwin->frame->on_click_right = windowCloseClick;
|
||||
wwin->frame->on_dblclick_right = windowCloseDblClick;
|
||||
wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
|
||||
wwin->frame->on_dblclick_titlebar = titlebarDblClick;
|
||||
wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
|
||||
wwin->frame->on_click_right = windowCloseClick;
|
||||
wwin->frame->on_dblclick_right = windowCloseDblClick;
|
||||
wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
|
||||
wwin->frame->on_dblclick_titlebar = titlebarDblClick;
|
||||
wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
|
||||
|
||||
wm_backend->window_select_events(wwin->client_win,
|
||||
wwin->event_mask & ~StructureNotifyMask);
|
||||
wm_backend->client_reparent(wwin->client_win, wwin->frame->core->window,
|
||||
0, wwin->frame->top_width);
|
||||
wm_backend->window_select_events(wwin->client_win, wwin->event_mask);
|
||||
wm_backend->window_select_events(wwin->client_win,
|
||||
wwin->event_mask & ~StructureNotifyMask);
|
||||
wm_backend->client_reparent(wwin->client_win, wwin->frame->core->window,
|
||||
0, wwin->frame->top_width);
|
||||
wm_backend->window_select_events(wwin->client_win, wwin->event_mask);
|
||||
|
||||
{
|
||||
int gx, gy;
|
||||
{
|
||||
int gx, gy;
|
||||
|
||||
wClientGetGravityOffsets(wwin, &gx, &gy);
|
||||
wClientGetGravityOffsets(wwin, &gx, &gy);
|
||||
|
||||
/* if gravity is to the south, account for the border sizes */
|
||||
if (gy > 0)
|
||||
y -= wwin->frame->top_width + wwin->frame->bottom_width;
|
||||
/* if gravity is to the south, account for the border sizes */
|
||||
if (gy > 0)
|
||||
y -= wwin->frame->top_width + wwin->frame->bottom_width;
|
||||
}
|
||||
|
||||
/*
|
||||
* wWindowConfigure() will init the client window's size
|
||||
* (wwin->client.{width,height}) and all other geometry
|
||||
* related variables (frame_x,frame_y) */
|
||||
wWindowConfigure(wwin, x, y, width, height);
|
||||
|
||||
/* to make sure the window receives it's new position after reparenting */
|
||||
wWindowSynthConfigureNotify(wwin);
|
||||
} else {
|
||||
/* Wayland: record geometry from normal hints; frame stays NULL */
|
||||
wwin->client.x = x;
|
||||
wwin->client.y = y;
|
||||
wwin->client.width = width;
|
||||
wwin->client.height = height;
|
||||
wwin->frame_x = x;
|
||||
wwin->frame_y = y;
|
||||
}
|
||||
|
||||
/*
|
||||
* wWindowConfigure() will init the client window's size
|
||||
* (wwin->client.{width,height}) and all other geometry
|
||||
* related variables (frame_x,frame_y) */
|
||||
wWindowConfigure(wwin, x, y, width, height);
|
||||
|
||||
/* to make sure the window receives it's new position after reparenting */
|
||||
wWindowSynthConfigureNotify(wwin);
|
||||
|
||||
/* Setup descriptors and save window to internal lists */
|
||||
if (wwin->main_window != None) {
|
||||
WApplication *app;
|
||||
|
|
@ -1205,10 +1215,12 @@ WWindow *wManageWindow(WScreen *scr, WNativeWindow window)
|
|||
}
|
||||
}
|
||||
|
||||
/* setup the frame descriptor */
|
||||
wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
|
||||
wwin->frame->core->descriptor.parent = wwin;
|
||||
wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
|
||||
if (wwin->frame) {
|
||||
/* setup the frame descriptor */
|
||||
wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
|
||||
wwin->frame->core->descriptor.parent = wwin;
|
||||
wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
|
||||
}
|
||||
|
||||
/* don't let windows go away if we die */
|
||||
wm_backend->client_add_to_save_set(window);
|
||||
|
|
@ -1227,35 +1239,22 @@ WWindow *wManageWindow(WScreen *scr, WNativeWindow window)
|
|||
else
|
||||
wClientSetState(wwin, NormalState, None);
|
||||
|
||||
if (wPreferences.superfluous && !wPreferences.no_animations && !scr->flags.startup &&
|
||||
if (wwin->frame && wPreferences.superfluous && !wPreferences.no_animations && !scr->flags.startup &&
|
||||
(wwin->transient_for == None || wwin->transient_for == scr->root_win) &&
|
||||
/*
|
||||
* The brain damaged idiotic non-click to focus modes will
|
||||
* have trouble with this because:
|
||||
*
|
||||
* 1. window is created and mapped by the client
|
||||
* 2. window is mapped by wmaker in small size
|
||||
* 3. window is animated to grow to normal size
|
||||
* 4. this function returns to normal event loop
|
||||
* 5. eventually, the EnterNotify event that would trigger
|
||||
* the window focusing (if the mouse is over that window)
|
||||
* will be processed by wmaker.
|
||||
* But since this event will be rather delayed
|
||||
* (step 3 has a large delay) the time when the event occurred
|
||||
* and when it is processed, the client that owns that window
|
||||
* will reject the XSetInputFocus() for it.
|
||||
*/
|
||||
(wPreferences.focus_mode == WKF_CLICK || wPreferences.auto_focus))
|
||||
DoWindowBirth(wwin);
|
||||
|
||||
wWindowMap(wwin);
|
||||
if (wwin->frame)
|
||||
wWindowMap(wwin);
|
||||
}
|
||||
|
||||
/* setup stacking descriptor */
|
||||
if (transientOwner)
|
||||
wwin->frame->core->stacking->child_of = transientOwner->frame->core;
|
||||
else
|
||||
wwin->frame->core->stacking->child_of = NULL;
|
||||
if (wwin->frame) {
|
||||
if (transientOwner)
|
||||
wwin->frame->core->stacking->child_of = transientOwner->frame->core;
|
||||
else
|
||||
wwin->frame->core->stacking->child_of = NULL;
|
||||
}
|
||||
|
||||
if (!scr->focused_window) {
|
||||
/* first window on the list */
|
||||
|
|
@ -1277,7 +1276,7 @@ WWindow *wManageWindow(WScreen *scr, WNativeWindow window)
|
|||
|
||||
/* raise is set to true if we un-hid the app when this window was born.
|
||||
* we raise, else old windows of this app will be above this new one. */
|
||||
if (raise)
|
||||
if (raise && wwin->frame)
|
||||
wRaiseFrame(wwin->frame->core);
|
||||
|
||||
/* Update name must come after WApplication stuff is done */
|
||||
|
|
@ -1288,7 +1287,8 @@ WWindow *wManageWindow(WScreen *scr, WNativeWindow window)
|
|||
wm_backend->server_ungrab();
|
||||
|
||||
/* Final preparations before window is ready to go */
|
||||
wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
|
||||
if (wwin->frame)
|
||||
wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
|
||||
|
||||
if (!wwin->flags.miniaturized && workspace == scr->current_workspace && !wwin->flags.hidden) {
|
||||
if (((transientOwner && transientOwner->flags.focused)
|
||||
|
|
@ -2317,6 +2317,9 @@ void wWindowSetKeyGrabs(WWindow * wwin)
|
|||
int i;
|
||||
WShortKey *key;
|
||||
|
||||
if (!wwin->frame)
|
||||
return; /* Wayland: no frame window to grab keys on */
|
||||
|
||||
for (i = 0; i < WKBD_LAST; i++) {
|
||||
key = &wKeyBindings[i];
|
||||
|
||||
|
|
|
|||
|
|
@ -1536,6 +1536,9 @@ void wNETWMCheckClientHints(WWindow *wwin, int *layer, int *workspace)
|
|||
unsigned long nitems_ret, bytes_after_ret;
|
||||
long *data = NULL;
|
||||
|
||||
if (!dpy)
|
||||
return; /* Wayland: no X11 NETWM properties */
|
||||
|
||||
if (XGetWindowProperty(dpy, wwin->client_win, net_wm_desktop, 0, 1, False,
|
||||
WA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret,
|
||||
&bytes_after_ret, (unsigned char **)&data) == Success && data) {
|
||||
|
|
@ -1642,6 +1645,9 @@ void wNETWMCheckInitialClientState(WWindow *wwin)
|
|||
wmessage("wNETWMCheckInitialClientState");
|
||||
#endif
|
||||
|
||||
if (!dpy)
|
||||
return; /* Wayland: no X11 NETWM initial state */
|
||||
|
||||
wNETWMShowingDesktop(wwin->screen_ptr, False);
|
||||
|
||||
updateWindowType(wwin);
|
||||
|
|
@ -1873,6 +1879,9 @@ int wNETWMGetPidForWindow(Window window)
|
|||
long *data = NULL;
|
||||
int pid;
|
||||
|
||||
if (!dpy)
|
||||
return 0; /* Wayland: no _NET_WM_PID property */
|
||||
|
||||
if (XGetWindowProperty(dpy, window, net_wm_pid, 0, 1, False,
|
||||
WA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret,
|
||||
&bytes_after_ret, (unsigned char **)&data) == Success && data) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
# loop (stays alive for 3 s, compositor still alive afterwards)
|
||||
# 8. (Phase 38) Per-toplevel view lifecycle: compositor logs "toplevel
|
||||
# mapped" when weston-simple-shm creates its XDG toplevel surface
|
||||
# 9. (Phase 39) wManageWindow called for mapped XDG toplevel: compositor
|
||||
# logs "wManageWindow succeeded" for the synthetic surface ID
|
||||
#
|
||||
# This test grows as wl_backend vtable slots are implemented.
|
||||
#
|
||||
|
|
@ -148,6 +150,11 @@ if command -v weston-simple-shm >/dev/null 2>&1; then
|
|||
grep -q 'toplevel mapped' /tmp/wl-smoke-stderr \
|
||||
|| die "compositor did not log 'toplevel mapped' for weston-simple-shm"
|
||||
echo " lifecycle check: toplevel mapped event logged"
|
||||
|
||||
# -- 9. Phase 39: wManageWindow must have succeeded -------------------
|
||||
grep -q 'wManageWindow succeeded' /tmp/wl-smoke-stderr \
|
||||
|| die "compositor did not log 'wManageWindow succeeded' (wManageWindow call failed)"
|
||||
echo " manage check: wManageWindow succeeded for weston-simple-shm toplevel"
|
||||
else
|
||||
echo " client check: skipped (weston-simple-shm not installed)"
|
||||
fi
|
||||
|
|
|
|||
Loading…
Reference in New Issue