Map synthetic move and resize affordances to the exact DAT cursors, make chat top chrome movable, and replace stale primary-panel height caps with a dynamic screen-edge constraint. This keeps the retained wrapper adaptation aligned with retail Dragbar/Resizebar behavior.
5 KiB
Retail window-control cursor pseudocode
Date: 2026-07-17
Question
Which cursors does the end-of-retail client show while hovering or operating window dragbars and resizebars, and how are they selected?
Named-retail mechanism
Widget cursor ownership
MediaMachine::Update_Cursor(owner, cursorMedia) // 0x00465A80
if cursorMedia.file is valid
owner.SetCursor(file, hotspotX, hotspotY)
else
owner.UnSetCursor()
UIElement::SetCursor(file, hotspotX, hotspotY) // 0x0045FF50
m_cursorDID = file
m_cursorHotX = hotspotX
m_cursorHotY = hotspotY
UIElementManager.CheckCursor()
UIElementManager::CheckCursor() // 0x0045ABF0
if mouseCapture != null and mouseCapture.HasCursor()
apply mouseCapture cursor
else if lastEntered != null and lastEntered.HasCursor()
apply lastEntered cursor
else
apply ClientUISystem default cursor
The important ownership rule is that the captured widget wins. A resize or move cursor therefore remains visible after the pointer leaves the original five-pixel control while the button is still held.
Window controls
UIElement_Resizebar::StartMouseResizing(point) // 0x0046B7E0
parent = GetParent()
edge = authored Left/Right/Top/Bottom attributes
m_mousePressed = true
parent.StartResizing(edge, point.x, point.y)
SetState(Pressed)
UIElement_Resizebar::StopMouseResizing() // 0x0046B8C0
SetState(Normal)
m_mousePressed = false
GetParent().StopResizing()
UIElement_Dragbar::StartMouseMoving(message) // 0x0046C760
if primary mouse button and parent is not already moving/resizing
m_mousePressed = true
parent.StartMovement(message.windowX, message.windowY)
SetState(Pressed)
UIElement_Dragbar::StopMouseMoving(message) // 0x0046C7C0
if pressed and primary mouse button
SetState(Normal)
m_mousePressed = false
GetParent().StopMovement()
Dragbar and Resizebar do not synthesize OS cursors in these methods. Their
LayoutDesc state media supplies MD_Data_Cursor; the generic
MediaMachine::Update_Cursor path above installs it on the element.
Installed end-of-retail DAT oracle
The production LayoutDesc records and portal DAT resolve these direct cursor
surfaces, all with hotspot (16, 16) pixels:
| Intent | RenderSurface DID | Observed authored use |
|---|---|---|
| Move window | 0x06006119 |
Type-2 Dragbar controls |
| Resize vertically | 0x06005E66 |
horizontal Type-9 Resizebar (main chat top edge and combat bottom edge) |
| Resize horizontally | 0x06006128 |
vertical Type-9 Resizebar |
| Resize NW-SE | 0x06006126 |
top-left and bottom-right Type-9 corners |
| Resize NE-SW | 0x06006127 |
bottom-left / opposite diagonal Type-9 corner |
All five surfaces are 32×32 PFID_A8R8G8B8 cursor images. Representative
LayoutDesc fixtures independently preserve the same media:
- main chat
0x21000006, element0x1000000F: vertical cursor0x06005E66at(16,16); - combat
0x21000073, Dragbar0x100006AE: move cursor0x06006119at(16,16); - combat corner/edge Resizebars:
0x06006126..0x06006128.
DatReaderWriter supplies these cursor records through the existing
LayoutDesc media decode. WorldBuilder's backend exposes the same architectural
boundary (SetCursor(cursorDataId, hotspot)) but leaves it unimplemented; it
does not provide a competing behavior interpretation.
acdream root cause and port
UiRoot already computes the active or hovered resize edges and window-move
ownership. CursorFeedbackController already translates those states into
WindowMove, ResizeHorizontal, ResizeVertical, and the two diagonal
semantic kinds. However, RetailCursorManager renders only a valid
UiCursorMedia override or the ClientUISystem global cursor. The semantic
window-control kind was never converted to media, so synthetic wrapper borders
and whole-window drag regions retained the normal pointer.
Port shape:
ResolveWindowControlCursor(kind):
WindowMove -> 0x06006119 @ (16,16)
ResizeHorizontal -> 0x06006128 @ (16,16)
ResizeVertical -> 0x06005E66 @ (16,16)
ResizeDiagonalNWSE -> 0x06006126 @ (16,16)
ResizeDiagonalNESW -> 0x06006127 @ (16,16)
UpdateCursor(root):
kind = resolve semantic interaction state
authored = captured-or-hovered element cursor, using retail precedence
if a synthetic resize edge owns the pointer or a resize/move operation owns capture
cursor = ResolveWindowControlCursor(kind)
else if authored is valid
cursor = authored
else
cursor = ResolveWindowControlCursor(kind)
render cursor; otherwise retain the ClientUISystem global cursor
Authored widget media therefore remains the first hover-time oracle. The shared fallback exists for retained wrapper borders and the accepted IA-12 whole-window drag adaptation, which have no authored Dragbar/Resizebar child. Once a synthetic operation starts, its control cursor wins just as retail's captured Dragbar or Resizebar wins.