================================================================================
EVIDENCE: Task 5 — wlr_fractional_scale_manager_v1 propagation chain
================================================================================

Goal: Verify that scale-change notifications reach surfaces when any output
      configuration changes (wlr-randr, hotplug, layout rejig, etc.).

================================================================================
PATH 1 (direct): outputmgrapplyortest() → updatemons()
================================================================================

  File:      src/peachwm.c
  Function:  outputmgrapplyortest()       (line 2553)
  Call site: line 2612 — updatemons(nullptr, nullptr);

  Triggered by:
    - outputmgrapply()  (line 2548 — from wlr_output_manager config apply)
    - outputmgrtest()   (line 2615 — from wlr_output_manager test)

  This path fires when a client (e.g. wlr-randr) sends a new output
  configuration.  After committing the per-head state and sending the
  success/failure response, updatemons() is called unconditionally.

  CONFIRMED ✅ — updatemons(nullptr, nullptr) at line 2612.

================================================================================
PATH 2 (indirect): output_layout.change signal → updatemons()
================================================================================

  Listener declaration: line 364
    static struct wl_listener layout_change = {.notify = updatemons};

  Signal wiring: line 3691
    wl_signal_add(&output_layout->events.change, &layout_change);

  This path fires when the output layout changes via any other route
  (e.g. hotplug, wlr_output_layout_add call inside updatemons itself).
  It is the "belt" to the "suspenders" of Path 1.

  Note: outputmgrapplyortest() calls wlr_output_layout_add() at line 2600,
        which itself triggers output_layout.change — so Path 2 also fires
        during Path 1.  updatemons() is idempotent (no ill effect from
        running twice in a single event cycle).

  CONFIRMED ✅ — layout_change.notify = updatemons at line 364,
                 wired at line 3691.

================================================================================
SCALE RE-NOTIFICATION HOOK (inside updatemons)
================================================================================

  File:      src/peachwm.c
  Function:  updatemons()                  (line 4101)
  Hook:      lines 4168–4201

  For each enabled monitor:

    [clients loop, line 4170]
    wl_list_for_each(c, &clients, link) {
      if (c->mon != m)
        continue;
      client_update_scale(c);                          // ← task 4 hook
      if (!client_is_x11(c) && c->surface.xdg) {
        struct wlr_xdg_popup *popup;
        wl_list_for_each(popup, &c->surface.xdg->popups, link)
          wlr_fractional_scale_v1_notify_scale(
              popup->base->surface, (double)m->wlr_output->scale);
      }
    }

    [layers loop, line 4181]
    for (int i = 0; i < 4; i++) {
      LayerSurface *l;
      wl_list_for_each(l, &m->layers[i], link) {
        layersurface_update_scale(l);                  // ← task 4 hook
        {
          struct wlr_scene_node *popup_node;
          wl_list_for_each(popup_node, &l->popups->children, link) {
            if (popup_node->type != WLR_SCENE_NODE_BUFFER)
              continue;
            struct wlr_scene_buffer *sb =
                wlr_scene_buffer_from_node(popup_node);
            struct wlr_scene_surface *ss =
                wlr_scene_surface_try_from_buffer(sb);
            if (ss && ss->surface)
              wlr_fractional_scale_v1_notify_scale(
                  ss->surface, (double)m->wlr_output->scale);
          }
        }
      }
    }

  This covers both regular xdg-toplevel clients and layer-shell surfaces
  (bars, backgrounds, OSDs), including their XDG popups.

  CONFIRMED ✅ — scale re-notification hook present and complete.

================================================================================
VERDICT: PROPAGATION CHAIN CONFIRMED ✅
================================================================================

  outputmgrapplyortest() → updatemons()   [direct:   line 2612]
  layout_change signal  → updatemons()   [indirect: lines 364, 3691]
  updatemons()          → client_update_scale(), layersurface_update_scale(),
                          wlr_fractional_scale_v1_notify_scale()  [lines 4168–4201]

  No code changes required.  The chain is complete.  Scale-change notifications
  will reach every surface (clients + layers + popups) whenever output
  configuration changes through ANY path.

  Test: wlr-randr --output DP-1 --scale 2   # triggers Path 1 via config apply
        # which calls updatemons, which re-notifies every surface on that output.
        # Also triggers Path 2 via wlr_output_layout_add calling events.change.

================================================================================
