Fix missing Open Mail button and bump to 1.4.9

- Recreate the Open Mail button if it is missing
- Restore its parent, position, text and click handler
- Ensure the button stays visible above the inbox UI
- Reapply the fix when the mailbox opens or updates
- Bump version to 1.4.9
This commit is contained in:
2026-09-14 07:17:16 +00:00
parent 0853d3854c
commit 6aab69a116
4 changed files with 77 additions and 6 deletions
+5 -1
View File
@@ -23,6 +23,10 @@ Target: Turtle WoW 1.18.x / Octo client.
- **`MailMailButton` nil crash:** upstream stores the real `SendMailMailButton` in a loose global named `MailMailButton`, then replaces the Blizzard global with a proxy table. If the saved global is missing or another UI addon changes it, `SendMailFrame_CanSend()` and `sendmail_clear()` crash while calling `Enable()` / `Disable()`. The compatibility layer now preserves a strong reference to the real button before the proxy swap, restores it when the mailbox opens, replaces the fragile CanSend hook, and uses a guarded clear routine.
- **Paired subject edit-box hardening:** the same proxy pattern is used for `MailSubjectEditBox`; the real edit box is now preserved and restored alongside the send button to avoid the equivalent follow-up failure.
## Fixed in 1.4.9
- **Missing `Open Mail` button:** upstream creates `TurtleMailOpenMailButton` only once in `inbox_load()` and assumes it will remain parented, positioned, and visible forever. If that creation path is interrupted or another mailbox/UI addon hides or re-parents the button, TurtleMail never recovers it. The compatibility layer now uses an idempotent inbox loader and an `ensure_open_mail_button()` recovery path that recreates the button if needed, restores its parent/anchor/text/click handler/frame level, and re-shows it on mailbox/inbox refreshes.
## Remaining architectural risks upstream
These are intentionally not rewritten in the compatibility layer because changing them would be much more invasive and could alter mail behavior:
@@ -44,4 +48,4 @@ The compatibility build was tested in-game on Turtle WoW 1.18.x and the reported
## Status
**1.4.8 is the current stable release.** The fixes remain isolated in `TurtleMailFix.lua` so upstream code stays easy to compare and future upstream changes remain easier to merge.
**1.4.9 is the current stable release.** The fixes remain isolated in `TurtleMailFix.lua` so upstream code stays easy to compare and future upstream changes remain easier to merge.
+4 -3
View File
@@ -76,7 +76,7 @@ When enabled, TurtleMail records sent and received mail information in its dedic
## 🔧 Turtle WoW compatibility
Version **1.4.8** extends the compatibility and safety layer for Turtle WoW 1.18.x environments.
Version **1.4.9** extends the compatibility and safety layer for Turtle WoW 1.18.x environments.
The compatibility work is isolated in `TurtleMailFix.lua` so the original TurtleMail code remains easier to compare with upstream versions.
@@ -96,6 +96,7 @@ The compatibility work is isolated in `TurtleMailFix.lua` so the original Turtle
- Rebound the safer `OnUpdate` handler correctly after loading the compatibility layer.
- Prevented the send queue from remaining stuck when an attachment becomes unavailable during sending.
- Fixed `MailMailButton` nil crashes while enabling/disabling or clearing the send form, and hardened the paired subject edit-box reference.
- Restored the missing **Open Mail** button by making its creation idempotent and reasserting its parent, position, visibility, click handler, and frame level when the mailbox refreshes.
The complete technical audit is available in [`AUDIT.md`](AUDIT.md).
@@ -130,11 +131,11 @@ TurtleMail includes localization support for:
Current stable version:
**1.4.8**
**1.4.9**
Based on upstream **TurtleMail 1.4.5**.
Version 1.4.8 adds an additional safeguard for the legacy send-button proxy used by TurtleMail. The earlier compatibility fixes remain unchanged.
Version 1.4.9 adds recovery for the **Open Mail** inbox button when its initial creation is interrupted or another UI addon hides/re-parents it. The earlier compatibility fixes remain unchanged.
## 🖼️ Screenshots
+1 -1
View File
@@ -2,7 +2,7 @@
## Interface: 11200
## Title: |cffabd473Turtle|cffffffffMail
## Author: shirsig/sica, Dusk-92 (compatibility fixes)
## Version: 1.4.8
## Version: 1.4.9
## Notes: Mailbox enhancement - Turtle WoW 1.18.x compatibility
## SavedVariables: TurtleMail_AutoCompleteNames
## SavedVariablesPerCharacter: TurtleMail_To TurtleMail_Point TurtleMail_Log
+67 -1
View File
@@ -8,7 +8,7 @@ local m = TurtleMail
local getn = table.getn
local function pack( ... ) return arg end
m.compat_version = "1.4.8"
m.compat_version = "1.4.9"
local DEFAULT_SENT_FILTERS = {
Money = 1,
@@ -179,6 +179,69 @@ local function restore_real_mail_widgets_for_upstream()
if edit_box then m.api.SendMailSubjectEditBox = edit_box end
end
-- The upstream Open Mail button is created only once in inbox_load(). If that
-- creation is skipped/interrupted, or another UI addon hides/re-parents the
-- button afterwards, TurtleMail never recreates it. Keep the button recoverable
-- whenever the mailbox/inbox is shown or refreshed.
local function ensure_open_mail_button()
local inbox = m.api.InboxFrame
if not inbox or not m.api.CreateFrame then return nil end
local button = m.api.TurtleMailOpenMailButton
if not button or type( button.SetPoint ) ~= "function" then
button = m.api.CreateFrame( "Button", "TurtleMailOpenMailButton", inbox, "UIPanelButtonTemplate" )
m.api.TurtleMailOpenMailButton = button
end
if button.SetParent then button:SetParent( inbox ) end
if button.ClearAllPoints then button:ClearAllPoints() end
button:SetPoint( "BOTTOM", inbox, "BOTTOM", -10, 90 )
if button.SetText then button:SetText( m.api.OPENMAIL or "Open Mail" ) end
local width = 120
local font_string = button.GetFontString and button:GetFontString()
if font_string and font_string.GetStringWidth then
width = math.max( 120, 30 + (font_string:GetStringWidth() or 0) )
end
if button.SetWidth then button:SetWidth( width ) end
if button.SetHeight then button:SetHeight( 25 ) end
if button.SetScript then button:SetScript( "OnClick", m.inbox_open_all ) end
if inbox.GetFrameLevel and button.SetFrameLevel then
button:SetFrameLevel( (inbox:GetFrameLevel() or 0) + 5 )
end
if button.Enable then button:Enable() end
if button.Show then button:Show() end
return button
end
-- Replace the fragile one-shot inbox loader with an idempotent version. This
-- preserves upstream behavior while making Open Mail recoverable instead of
-- relying on the initial CreateFrame call succeeding forever.
function m.inbox_load()
if m.api.InboxFrame and m.api.InboxFrame.EnableMouse then
m.api.InboxFrame:EnableMouse( false )
end
ensure_open_mail_button()
for i = 1, 7 do
local auction_texture = m.api[ "TurtleMailAuctionIcon" .. i .. "Texture" ]
local returned_texture = m.api[ "TurtleMailReturnedArrow" .. i .. "Texture" ]
local color = m.api.NORMAL_FONT_COLOR
if color and auction_texture and auction_texture.SetVertexColor then
auction_texture:SetVertexColor( color.r, color.g, color.b )
end
if color and returned_texture and returned_texture.SetVertexColor then
returned_texture:SetVertexColor( color.r, color.g, color.b )
end
end
end
-- SavedVariables are not guaranteed to have a valid schema. Repair them before
-- the original handlers touch nested fields.
do
@@ -364,6 +427,7 @@ function m.MAIL_SHOW()
-- recovers if another UI addon changed those globals after addon loading.
ensure_send_mail_button()
ensure_subject_edit_box()
ensure_open_mail_button()
if not m.api.MailFrame then return end
@@ -466,6 +530,8 @@ end
-- Hide stale AH/returned icons on rows that no longer contain mail.
function m.MAIL_INBOX_UPDATE()
ensure_open_mail_button()
if m.inbox_opening then
m.inbox_update = true
end