windowmaker-wl/ACTION_PLAN_PROMPTS.md

26 KiB

Prompt Templates for Mechanical Wayland Port Tasks

Reference Tables (embed in every prompt)

X11 Event Type → WMEvent Type

KeyPress/KeyRelease       → WME_KEY_PRESS/WME_KEY_RELEASE     → event->u.key.*
ButtonPress/ButtonRelease → WME_BUTTON_PRESS/WME_BUTTON_RELEASE → event->u.button.*
MotionNotify              → WME_MOTION                         → event->u.motion.*
EnterNotify/LeaveNotify   → WME_ENTER/WME_LEAVE               → event->u.crossing.*
Expose                    → WME_EXPOSE                         → event->u.expose.*
ConfigureNotify           → WME_CONFIGURE                      → event->u.configure.*
ConfigureRequest          → WME_CONFIGURE_REQUEST              → event->u.configureRequest.*
MapNotify                 → WME_MAP                            → event->u.lifecycle.*
MapRequest                → WME_MAP_REQUEST                    → event->u.mapRequest.*
UnmapNotify               → WME_UNMAP                          → event->u.lifecycle.*
DestroyNotify             → WME_DESTROY                        → event->u.lifecycle.*
FocusIn/FocusOut          → WME_FOCUS_IN/WME_FOCUS_OUT        → event->u.focus.*
PropertyNotify            → WME_PROPERTY                       → event->u.property.*
ClientMessage             → WME_CLIENT_MESSAGE                 → event->u.clientMessage.*
SelectionNotify           → WME_SELECTION                      → event->u.selection.*
SelectionRequest          → WME_SELECTION_REQUEST              → event->u.selection.*  (check)
SelectionClear            → WME_SELECTION_CLEAR                → event->u.selection.*  (check)
VisibilityNotify          → WME_VISIBILITY                     → event->u.visibility.*
ColormapNotify            → WME_COLORMAP                       → event->u.colormap.*
MappingNotify             → WME_MAPPING                        → event->u.mapping.*
ReparentNotify            → WME_REPARENT                       → event->u.reparent.*

X11 Event Field → WMEvent Field

event->xkey.keycode       → event->u.key.keycode
event->xkey.state         → event->u.key.state
event->xkey.time          → event->u.key.time
event->xkey.window        → event->u.key.window
event->xkey.x, y          → event->u.key.x, y
event->xkey.x_root        → event->u.key.x_root

event->xbutton.button     → event->u.button.button
event->xbutton.state      → event->u.button.state
event->xbutton.time       → event->u.button.time
event->xbutton.window     → event->u.button.window
event->xbutton.x, y       → event->u.button.x, y
event->xbutton.x_root     → event->u.button.x_root

event->xmotion.state      → event->u.motion.state
event->xmotion.time       → event->u.motion.time
event->xmotion.window     → event->u.motion.window
event->xmotion.x, y       → event->u.motion.x, y
event->xmotion.x_root     → event->u.motion.x_root

event->xcrossing.window   → event->u.crossing.window
event->xcrossing.state    → event->u.crossing.state
event->xcrossing.time     → event->u.crossing.time
event->xcrossing.mode     → event->u.crossing.mode
event->xcrossing.detail   → event->u.crossing.detail

event->xconfigure.window  → event->u.configure.window
event->xconfigure.x, y    → event->u.configure.x, y
event->xconfigure.width   → event->u.configure.width
event->xconfigure.height  → event->u.configure.height

event->xclient.data.l[N]  → event->u.clientMessage.data.l[N]
event->xclient.message_type → event->u.clientMessage.atom
event->xclient.window     → event->u.clientMessage.window

event->xproperty.atom     → event->u.property.atom
event->xproperty.time     → event->u.property.time
event->xproperty.window   → event->u.property.window

Template 1: Change Function Signature from XEvent* to WMEvent*

Use for: A5.1, B.3, E.3, E.4 (and any function that takes an X11 event type as parameter)

TASK: Change the function {{FUNCTION_NAME}} in {{FILE}} from taking an X11 event
type to taking the backend-neutral WMEvent type.

GOVERNING PRINCIPLE: Policy code in src/ must never reference X11 types. The
backend-neutral event type is `WMEvent` (defined in WINGs/WINGs/WMEvent.h).

STEPS:

1. Read {{FILE}} and {{HEADER_FILE}} to find the function signature.

2. Change the parameter type:
   OLD: {{OLD_PARAM_TYPE}} *{{PARAM_NAME}}
   NEW: WMEvent *{{PARAM_NAME}}

3. Update the header file ({{HEADER_FILE}}) with the same signature change.

4. Inside the function body, replace every X11 event field access:
   - event->xkey.*       → event->u.key.*
   - event->xbutton.*    → event->u.button.*
   - event->xmotion.*    → event->u.motion.*
   - event->xcrossing.*  → event->u.crossing.*
   - event->xconfigure.* → event->u.configure.*
   - event->xclient.*    → event->u.clientMessage.*
   - event->xproperty.*  → event->u.property.*
   - event->type == MotionNotify  → event->type == WME_MOTION
   - event->type == ButtonPress   → event->type == WME_BUTTON_PRESS
   - event->type == ButtonRelease → event->type == WME_BUTTON_RELEASE
   - event->type == KeyPress      → event->type == WME_KEY_PRESS
   (Use the X11→WMEvent mapping table for the complete list.)

5. Find ALL call sites by grepping for {{FUNCTION_NAME}} across src/ and WINGs/.
   At each call site:
   - If the caller has a `WMEvent`, pass it directly.
   - If the caller has an `XEvent*` via `_x11_raw`, change to pass the `WMEvent`
     directly (this eliminates the `_x11_raw` access).

6. If the function used `XWindowChanges` or other X11 structs internally to call
   Xlib functions, replace those Xlib calls with wm_backend->*() vtable calls
   using the WMEvent fields.

VERIFICATION:
- `grep -rn '{{OLD_PARAM_TYPE}}' {{FILE}} {{HEADER_FILE}}` returns zero matches.
- `grep -rn '_x11_raw.*{{FUNCTION_NAME}}\|{{FUNCTION_NAME}}.*_x11_raw' src/` returns
  zero matches.
- The code compiles.

CONSTRAINTS:
- Do NOT add `#ifdef` guards. Do NOT add `if (dpy)` checks.
- Do NOT change the function's logic — only its interface types.
- Do NOT modify files in src/backend/.

Template 2: Eliminate _x11_raw Access

Use for: R.1, R.2, R.3, E.1, and individual sites in E.2

TASK: Eliminate the `_x11_raw` escape hatch at {{FILE}}:{{LINE}}.

GOVERNING PRINCIPLE: Policy code must never reach through the WMEvent abstraction
to access the raw X11 event. The `_x11_raw` field exists only for backend code.

CONTEXT: At line {{LINE}}, the code does:
    XEvent *xev = (XEvent *)event->_x11_raw;
and then accesses xev->{{XEVENT_FIELD}} to get {{WHAT_IT_NEEDS}}.

STEPS:

1. Read {{FILE}} around line {{LINE}} (±30 lines) to understand what information
   is extracted from the raw XEvent.

2. Identify the equivalent field in the WMEvent struct:
   {{XEVENT_FIELD}} → {{WMEVENT_FIELD}}
   (Use the X11→WMEvent field mapping table.)

3. Replace the `_x11_raw` cast and XEvent field access with direct WMEvent access:
   OLD: XEvent *xev = (XEvent *)event->_x11_raw;
        ... xev->{{XEVENT_FIELD}} ...
   NEW: ... event->{{WMEVENT_FIELD}} ...

4. Delete the `XEvent *xev` declaration and the cast.

5. If the raw XEvent was passed to another function (e.g., `someFunc(xev)`),
   that function's signature must also be changed (use Template 1).

6. If the raw XEvent was passed to a `wm_backend->*()` vtable call, change the
   vtable call to accept `WMEvent*` instead of `void*`. Update the vtable
   signature in backend.h, and update both x11_backend.c and wl_backend.c
   implementations. The X11 backend extracts `_x11_raw` internally; the Wayland
   backend uses WMEvent fields directly.

VERIFICATION:
- `grep -n '_x11_raw' {{FILE}}` shows one fewer match than before.
- The code compiles.

CONSTRAINTS:
- Do NOT add NULL checks on `_x11_raw`. Do NOT add fallback paths.
- If the information needed is NOT available in WMEvent, STOP and report what
  field is missing. Do not invent a workaround.

Template 3: Replace Direct Xlib Call with wm_backend->*() Vtable Call

Use for: C.1, R.4, R.5, B.1, and any src/*.c file with direct Xlib calls

TASK: Replace the direct Xlib call {{XLIB_FUNCTION}} at {{FILE}}:{{LINE}} with
the backend vtable call {{VTABLE_SLOT}}.

GOVERNING PRINCIPLE: Policy code in src/ calls display operations exclusively
through `wm_backend->*()`. Direct Xlib calls are forbidden.

CONTEXT: The global `wm_backend` pointer is declared in src/backend/backend.h:
    extern const WMBackend *wm_backend;

STEPS:

1. Read {{FILE}} around line {{LINE}} (±10 lines) to understand the Xlib call
   and its arguments.

2. Find the matching vtable slot in src/backend/backend.h:
   `grep -n '{{VTABLE_SLOT}}' src/backend/backend.h`
   Read the slot's signature and documentation comment.

3. Replace the Xlib call:
   OLD: {{XLIB_FUNCTION}}(dpy, {{ARGS}});
   NEW: wm_backend->{{VTABLE_SLOT}}({{TRANSLATED_ARGS}});

   Argument translation rules:
   - Drop `dpy` (the backend knows its own display connection).
   - Drop `GC` arguments (the backend manages its own GCs).
   - `scr->root_win` → `scr` (the backend knows the root window).
   - X11 `Window` → `WNativeWindow` (same underlying type, no cast needed).
   - X11 `Pixmap` → `Pixmap` (same type in both backends).

4. If the vtable slot does NOT exist, STOP and report:
   "Need new vtable slot: {{PROPOSED_SIGNATURE}}"
   Do not add the slot yourself.

5. Remove any now-unused `#include` of X11 headers if this was the last Xlib
   call in the file.

VERIFICATION:
- `grep -n '{{XLIB_FUNCTION}}' {{FILE}}` shows one fewer match.
- The code compiles.

CONSTRAINTS:
- Do NOT add `#ifdef` guards or `if (dpy)` checks.
- Do NOT modify files in src/backend/.
- One Xlib call per task. Do not batch.

Template 4: Guard X11-Only Code Block in WINGs

Use for: D.1, D.2, D.11, and WINGs files where X11 code must be skipped on Wayland

TASK: Guard the X11-only code block at {{FILE}}:{{START_LINE}}-{{END_LINE}} so it
only executes when running on the X11 backend.

GOVERNING PRINCIPLE: WINGs code uses `scr->display != NULL` to detect the X11
backend. When `scr->display` is NULL, the Wayland backend is active and X11
calls must be skipped.

STEPS:

1. Read {{FILE}} from line {{START_LINE}} to {{END_LINE}}.

2. Confirm every line in this range calls Xlib functions or uses X11 types that
   have no meaning on Wayland (GC, XCreateGC, XInternAtom, etc.).

3. Wrap the block:
   ```c
   if (scr->display) {
       // ... existing X11 code unchanged ...
   }

Where scr is the W_Screen* in scope. Find it via:

  • Direct variable scr or scrPtr
  • view->screen
  • WMWidgetScreen(widget)
  1. If the Wayland backend needs equivalent behavior (e.g., the code creates cursors or interns atoms), add an else block that calls the appropriate backend vtable:
    if (scr->display) {
        // X11 path
    } else {
        // Wayland path — use scr->viewBackend->*() or scr->renderBackend->*()
    }
    
    If no Wayland equivalent is needed (e.g., GC creation), the else is omitted.

VERIFICATION:

  • The code compiles.
  • Running with WMAKER_USE_WAYLAND=1 does not crash in this code path (the X11 block is skipped).

CONSTRAINTS:

  • Do NOT move the code to a separate file. This template is for cases where the X11 code is small (< 50 lines) and inline guarding is cleaner than a split.
  • Do NOT delete the X11 code. It must continue to work for the X11 backend.
  • The guard condition is always if (scr->display), never #ifdef WAYLAND.

---

## Template 5: Split File into `_x11.c` / `_wl.c` Backend Pair

**Use for**: D.3, D.5, D.6, and any WINGs file that is entirely X11-specific

TASK: Split {{FILE}} into an X11 backend file, a Wayland backend file, and a thin dispatch layer.

GOVERNING PRINCIPLE: WINGs uses five backend vtables (view, event, render, font, color). Files that are entirely X11-specific should be split into _x11/_wl pairs following the existing pattern (e.g., wcolor.c / wcolor_x11.c / wcolor_wl.c).

EXISTING PATTERN (use as reference):

  • WINGs/wcolor.c — dispatch layer, calls scr->colorBackend->*()
  • WINGs/wcolor_x11.c — X11 implementation, exports W_ColorBackendX11
  • WINGs/wcolor_wl.c — Wayland implementation, exports W_ColorBackendWL

STEPS:

  1. Read {{FILE}} completely. Identify all public functions (declared in headers).

  2. Rename {{FILE}} → {{FILE_BASE}}_x11.c. Keep all code unchanged.

  3. Create {{FILE_BASE}}_wl.c with stub implementations of every public function. Each stub should either:

    • Implement the Wayland equivalent if straightforward
    • Call wwarning("{{FUNCTION}}: not yet implemented for Wayland") and return a safe default (NULL, 0, False)
  4. Create {{FILE_BASE}}.c as a dispatch layer. For each public function:

    ReturnType PublicFunction(args...) {
        if (scr->display)
            return x11_PublicFunction(args...);
        else
            return wl_PublicFunction(args...);
    }
    

    OR, if a vtable is more appropriate, define a new backend struct in WINGsP.h.in following the existing pattern (W_ColorBackend, W_FontBackend, etc.).

  5. Update WINGs/Makefile.am:

    • Remove {{FILE_BASE}}.c from the source list (it was renamed)
    • Add {{FILE_BASE}}.c, {{FILE_BASE}}_x11.c, {{FILE_BASE}}_wl.c
  6. Update any header files that declare the public functions — no signature changes needed.

VERIFICATION:

  • make -C WINGs compiles successfully.
  • The X11 backend path is unchanged (existing behavior preserved).
  • grep -rn 'X[A-Z][a-z]' WINGs/{{FILE_BASE}}.c returns zero (dispatch layer has no Xlib calls).

CONSTRAINTS:

  • The _wl.c stubs may be incomplete. That is acceptable. Mark incomplete stubs with /* TODO: Wayland implementation */.
  • Do NOT change any function signatures.
  • Do NOT modify {{FILE_BASE}}_x11.c beyond the rename. All existing code stays.

---

## Template 6: Replace Xlib Drawing Call with WINGs Render Backend

**Use for**: D.4, D.7, D.8, D.9, D.10, and WPrefs.app drawing (E.5a-c)

TASK: Replace the Xlib drawing call {{XLIB_CALL}} at {{FILE}}:{{LINE}} with a WINGs render backend call.

GOVERNING PRINCIPLE: Widget code draws through scr->renderBackend->*(). Direct Xlib drawing calls (XFillRectangle, XDrawLine, XCopyArea, etc.) are forbidden in non-_x11.c files.

RENDER BACKEND VTABLE (from WINGsP.h.in): scr->renderBackend->pixmap_create(rctx, width, height, depth) scr->renderBackend->pixmap_free(rctx, pm) scr->renderBackend->pixmap_copy(rctx, src, dst, sx, sy, w, h, dx, dy) scr->renderBackend->draw_line(rctx, d, color, x1, y1, x2, y2) scr->renderBackend->draw_rect(rctx, d, color, x, y, w, h) scr->renderBackend->fill_rect(rctx, d, color, x, y, w, h) scr->renderBackend->fill_polygon(rctx, d, color, points, npoints) scr->renderBackend->fill_arc(rctx, d, color, x, y, w, h, angle1, angle2) scr->renderBackend->composite_pixmap(rctx, dst, src, sx, sy, w, h, dx, dy)

Where: rctx = scr->renderBackendCtx d = the target WMDrawable (Pixmap or window's drawable) color = a WMColor* (obtain via WMColorGC pattern → WMColor*)

STEPS:

  1. Read {{FILE}} around line {{LINE}} (±5 lines).

  2. Identify the Xlib call and its arguments.

  3. Map to the render backend equivalent: XFillRectangle(dpy, d, gc, x, y, w, h) → scr->renderBackend->fill_rect(scr->renderBackendCtx, d, color, x, y, w, h)

    XDrawLine(dpy, d, gc, x1, y1, x2, y2) → scr->renderBackend->draw_line(scr->renderBackendCtx, d, color, x1, y1, x2, y2)

    XDrawRectangle(dpy, d, gc, x, y, w, h) → scr->renderBackend->draw_rect(scr->renderBackendCtx, d, color, x, y, w, h)

    XCopyArea(dpy, src, dst, gc, sx, sy, w, h, dx, dy) → scr->renderBackend->pixmap_copy(scr->renderBackendCtx, src, dst, sx, sy, w, h, dx, dy)

    XCreatePixmap(dpy, drawable, w, h, depth) → scr->renderBackend->pixmap_create(scr->renderBackendCtx, w, h, depth)

    XFreePixmap(dpy, pm) → scr->renderBackend->pixmap_free(scr->renderBackendCtx, pm)

    XFillPolygon(dpy, d, gc, points, npoints, shape, mode) → scr->renderBackend->fill_polygon(scr->renderBackendCtx, d, color, points, npoints)

    XFillArc(dpy, d, gc, x, y, w, h, angle1, angle2) → scr->renderBackend->fill_arc(scr->renderBackendCtx, d, color, x, y, w, h, angle1, angle2)

  4. For the color argument: the Xlib code uses a GC with a foreground color. Find where the GC's foreground was set (look for XSetForeground or WMColorGC(someColor)). Use that WMColor* directly.

  5. For scr: find the WMScreen in scope. Common patterns:

    • WMWidgetScreen(widget)
    • view->screen
    • local variable scr

VERIFICATION:

  • grep -n '{{XLIB_CALL}}' {{FILE}} shows one fewer match.
  • The code compiles.

CONSTRAINTS:

  • One call replacement per task.
  • If the GC was created with XCreateGC just for this drawing sequence, and this is the last use, also delete the XCreateGC and XFreeGC calls.
  • Do NOT change drawing logic (coordinates, colors, order).

---

## Template 7: Remove Compile-Time `#ifdef` Guard Using Backend-Neutral API

**Use for**: A4.1, B.2, H.1, R.7, and any `#ifdef USE_XINERAMA` / `#ifdef USE_XSHAPE` / `#ifdef USE_DOCK_XDND` site

TASK: Remove the compile-time guard #ifdef {{GUARD_NAME}} at {{FILE}}:{{LINE}} and replace the guarded code with a backend-neutral API call.

GOVERNING PRINCIPLE: No #ifdef guards for backend-specific features in policy code. Feature availability is determined at runtime by the backend vtable.

STEPS:

  1. Read {{FILE}} around line {{LINE}}. Identify the #ifdef {{GUARD_NAME}} block and the corresponding #else / #endif.

  2. Understand what the guarded code does:

    • USE_XINERAMA: queries per-monitor geometry
    • USE_XSHAPE: queries window shape
    • USE_DOCK_XDND: sets up XDND awareness
    • USE_MWM_HINTS: reads Motif hints
    • USE_RANDR: handles RandR events
  3. Identify the backend-neutral replacement:

    • Xinerama monitor queries → wGetHeadForPoint(scr, point), wGetUsableAreaForHead(scr, head), wGetRectForHead(scr, head). These functions already exist and are backend-abstracted.
    • XShape queries → wm_backend->window_get_shape() or equivalent vtable slot.
    • XDND setup → move into the backend's appicon_show implementation.
    • MWM hints → wm_backend->client_get_mwm_hints() or equivalent vtable slot.
  4. Replace the #ifdef / #else / #endif with the backend-neutral code. Delete both the guarded block and the else block. Write one unified path.

  5. If the #ifdef block called Xlib functions that have no vtable equivalent, STOP and report: "Need vtable slot for {{OPERATION}}".

VERIFICATION:

  • grep -n '{{GUARD_NAME}}' {{FILE}} shows one fewer match.
  • The code compiles with and without the feature flag defined.

CONSTRAINTS:

  • Do NOT add a different #ifdef. Do NOT add runtime if (dpy) checks.
  • The replacement must work on both X11 and Wayland backends.
  • If the #else block was empty (feature simply absent), the replacement is to call the vtable slot unconditionally — the Wayland backend returns a sensible default (e.g., "no shape", "single head").

---

## Template 8: Replace Xlib Call in WPrefs.app with WINGs API

**Use for**: E.5 sub-tasks (all WPrefs.app Xlib elimination)

TASK: Replace the Xlib call {{XLIB_CALL}} at WPrefs.app/{{FILE}}:{{LINE}} with the equivalent WINGs public API call.

GOVERNING PRINCIPLE: WPrefs.app is a WINGs client application. It must use only WINGs public APIs (declared in WINGs/WINGs/WINGs.h), never Xlib directly. WINGs routes all operations through its backend vtables internally.

WINGS API EQUIVALENTS: XFillRectangle(dpy, d, WMColorGC(c), x, y, w, h) → WMFillRectangle(scr, d, c, x, y, w, h) (if WMFillRectangle does not exist, use: scr->renderBackend->fill_rect(scr->renderBackendCtx, d, c, x, y, w, h))

XDrawLine(dpy, d, WMColorGC(c), x1, y1, x2, y2)
  → WMDrawLine(scr, d, c, x1, y1, x2, y2)
     (if WMDrawLine does not exist, use:
      scr->renderBackend->draw_line(scr->renderBackendCtx, d, c, x1, y1, x2, y2))

XCopyArea(dpy, src, dst, gc, sx, sy, w, h, dx, dy)
  → WMCopyArea(scr, src, dst, sx, sy, w, h, dx, dy)
     (if WMCopyArea does not exist, use:
      scr->renderBackend->pixmap_copy(scr->renderBackendCtx, src, dst, sx, sy, w, h, dx, dy))

XCreatePixmap(dpy, parent, w, h, depth)
  → WMCreatePixmap(scr, w, h, depth, False)  [returns WMPixmap*]
     then use WMGetPixmapXID(pixmap) to get the drawable

XFreePixmap(dpy, pm)
  → WMReleasePixmap(pixmap)  [if using WMPixmap*]
     or scr->renderBackend->pixmap_free(scr->renderBackendCtx, pm)

XCreateGC / XFreeGC
  → DELETE. WINGs manages GCs internally. Use WMColor* for color selection.

XParseColor(dpy, cmap, name, &xcolor)
  → WMCreateNamedColor(scr, name, True)  [returns WMColor*]

XGrabKeyboard / XUngrabKeyboard
  → No direct WINGs equivalent. Use:
    scr->viewBackend->keyboard_grab(scr->viewBackendCtx, view)
    (if slot exists; otherwise STOP and report)

XGrabPointer / XUngrabPointer
  → No direct WINGs equivalent. Use:
    scr->viewBackend->pointer_grab(scr->viewBackendCtx, view)
    (if slot exists; otherwise STOP and report)

XOpenDisplay
  → WMOpenScreen(display_name)  [in main.c initialization]

XSendEvent (for WM commands)
  → Write to defaults database + send SIGHUP, or use a WINGs notification.
    STOP and report if unclear.

STEPS:

  1. Read WPrefs.app/{{FILE}} around line {{LINE}} (±10 lines).
  2. Identify the Xlib call and its purpose.
  3. Find the WINGs equivalent from the table above.
  4. Replace the call. Adjust variable types if needed (e.g., GC gc → delete, XColor xcolor → WMColor *color).
  5. If the WINGs API function does not exist, use the renderBackend/viewBackend vtable call directly (WPrefs.app includes WINGsP.h for internal access).

VERIFICATION:

  • grep -n '{{XLIB_CALL}}' WPrefs.app/{{FILE}} shows one fewer match.
  • The code compiles.

CONSTRAINTS:

  • One call replacement per task.
  • Prefer WINGs public API over direct vtable access.
  • Do NOT add #ifdef guards or if (dpy) checks.

---

## Template 9: Verify File is X11-Free

**Use for**: F.2, F.3, F.4, G.1, I.1, I.2, C.3, H.5, and any verification task

TASK: Verify that {{FILE}} has no X11 dependencies that would break on the Wayland backend.

STEPS:

  1. Run: grep -nE '\bX[A-Z][a-z]' {{FILE}} This finds direct Xlib function calls. EXPECTED: {{EXPECTED_XLIB_COUNT}} matches.

  2. Run: grep -nE '\bDisplay\b|\bXEvent\b|\bXImage\b|\bXColor\b' {{FILE}} This finds X11 type usage. EXPECTED: {{EXPECTED_TYPE_COUNT}} matches.

  3. Run: grep -n '_x11_raw' {{FILE}} This finds raw event escape hatches. EXPECTED: 0 matches.

  4. Run: grep -n '#ifdef.*USE_X\|#ifdef.*HAVE_X\|#ifdef.*XINERAMA\|#ifdef.*XSHAPE\|#ifdef.*XDND' {{FILE}} This finds X11 feature guards. EXPECTED: {{EXPECTED_IFDEF_COUNT}} matches.

  5. If any count exceeds expected:

    • For each unexpected match, report the line number and the X11 reference.
    • Classify as: (a) actual dependency, (b) comment/string, (c) type used but never passed to Xlib.

REPORT FORMAT:

FILE: {{FILE}}
Xlib calls:    N (expected {{EXPECTED_XLIB_COUNT}})
X11 types:     N (expected {{EXPECTED_TYPE_COUNT}})
_x11_raw:      N (expected 0)
#ifdef guards:  N (expected {{EXPECTED_IFDEF_COUNT}})
STATUS: CLEAN / NEEDS WORK
ISSUES: (list any unexpected findings)

CONSTRAINTS:

  • Do NOT modify the file. This is a read-only verification task.
  • Report findings exactly. Do not interpret or fix.

---

## Template 10: Batch Instantiation Helper

**Use for**: Generating concrete prompts from templates + the action plan

Given the action plan task {{TASK_ID}}, instantiate the appropriate template.

ACTION PLAN TASK: ID: {{TASK_ID}} File(s): {{FILES}} Operation: {{OPERATION_SUMMARY}} Xlib calls to eliminate: {{COUNT}} Blocked by: {{DEPENDENCIES}}

Select the template:

  • Function signature change (XEvent* → WMEvent*) → Template 1
  • _x11_raw elimination → Template 2
  • Direct Xlib → wm_backend vtable → Template 3
  • Guard X11 block in WINGs → Template 4
  • Split into _x11/_wl pair → Template 5
  • Xlib drawing → WINGs render backend → Template 6
  • Remove #ifdef guard → Template 7
  • WPrefs.app Xlib → WINGs API → Template 8
  • Verification only → Template 9

Fill in ALL template variables from the action plan data and the codebase. Include exact line numbers (use grep -n to find current line numbers, as they may have shifted from the original analysis).

Output the fully instantiated prompt, ready to hand to an agent.


---

## Usage Notes

1. **One task per prompt.** Never batch multiple Xlib call replacements into a single prompt. The agent should make one surgical change, verify it compiles, and stop.

2. **Always include the mapping tables.** The X11→WMEvent type and field mapping tables should be included verbatim in every Template 1 and Template 2 instantiation. The agent needs them as reference, not from memory.

3. **Line numbers drift.** Before instantiating a template, re-grep for the exact current line number. The analysis line numbers are from the initial read and will shift as changes accumulate.

4. **Compilation is the gate.** Every task ends with "the code compiles." If it doesn't, the task is not done. The agent should fix compilation errors before reporting completion.

5. **STOP conditions are real.** Templates 3, 6, 7, and 8 include "STOP and report" conditions for missing vtable slots or APIs. The agent must actually stop — not invent a workaround. Missing infrastructure is a signal to create a new task, not to hack around it.

6. **Wave ordering matters.** Wave 1 tasks are independent and can be parallelized. Wave 2 tasks depend on Wave 1. Wave 3 (WPrefs.app) depends on Wave 2. Respect this ordering when dispatching to agents.