diff --git a/AUDIT.md b/AUDIT.md index e89606b..b34b55e 100644 --- a/AUDIT.md +++ b/AUDIT.md @@ -25,7 +25,11 @@ Target: Turtle WoW 1.18.x / Octo client. ## 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. +- **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 and restores its parent/anchor/text/click handler/frame level. + +## Fixed in 1.4.10 + +- **First mailbox-open freeze/stutter after the 1.4.9 recovery fix:** 1.4.9 called `ensure_open_mail_button()` on every `MAIL_INBOX_UPDATE`. Initial inbox population can emit a burst of those events, so the button was repeatedly re-parented, re-anchored, re-labeled, resized, and given a new frame level. 1.4.10 removes that work from `MAIL_INBOX_UPDATE` and makes `ensure_open_mail_button()` state-aware, so it only mutates the UI when the button is missing, hidden, moved, re-parented, or otherwise incorrect. ## Remaining architectural risks upstream @@ -48,4 +52,4 @@ The compatibility build was tested in-game on Turtle WoW 1.18.x and the reported ## Status -**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. +**1.4.10 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. diff --git a/README.md b/README.md index 0639506..86df378 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ When enabled, TurtleMail records sent and received mail information in its dedic ## 🔧 Turtle WoW compatibility -Version **1.4.9** extends the compatibility and safety layer for Turtle WoW 1.18.x environments. +Version **1.4.10** 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,7 +96,8 @@ 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. +- Restored the missing **Open Mail** button with an idempotent recovery path. +- Reduced first-open mailbox stutter by removing Open Mail layout repair from `MAIL_INBOX_UPDATE` and only changing the button when its state is actually wrong. The complete technical audit is available in [`AUDIT.md`](AUDIT.md). @@ -131,11 +132,11 @@ TurtleMail includes localization support for: Current stable version: -**1.4.9** +**1.4.10** Based on upstream **TurtleMail 1.4.5**. -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. +Version 1.4.10 keeps the **Open Mail** recovery from 1.4.9 but makes it lightweight: the button is repaired on load/mailbox open only when needed, instead of being re-parented and re-anchored on every inbox refresh. This avoids repeated layout work during the initial mailbox update burst. ## 🖼️ Screenshots diff --git a/TurtleMail.toc b/TurtleMail.toc index 7f0294d..2f6bbde 100644 --- a/TurtleMail.toc +++ b/TurtleMail.toc @@ -2,7 +2,7 @@ ## Interface: 11200 ## Title: |cffabd473Turtle|cffffffffMail ## Author: shirsig/sica, Dusk-92 (compatibility fixes) -## Version: 1.4.9 +## Version: 1.4.10 ## Notes: Mailbox enhancement - Turtle WoW 1.18.x compatibility ## SavedVariables: TurtleMail_AutoCompleteNames ## SavedVariablesPerCharacter: TurtleMail_To TurtleMail_Point TurtleMail_Log diff --git a/TurtleMailFix.lua b/TurtleMailFix.lua index 032332c..65d032d 100644 --- a/TurtleMailFix.lua +++ b/TurtleMailFix.lua @@ -8,7 +8,7 @@ local m = TurtleMail local getn = table.getn local function pack( ... ) return arg end -m.compat_version = "1.4.9" +m.compat_version = "1.4.10" local DEFAULT_SENT_FILTERS = { Money = 1, @@ -181,40 +181,92 @@ 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. +-- button afterwards, TurtleMail never recreates it. Keep the button recoverable, +-- but only mutate its layout when something is actually wrong. This avoids doing +-- repeated SetParent/ClearAllPoints/SetPoint work during inbox refresh bursts. 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 + local created = false if not button or type( button.SetPoint ) ~= "function" then button = m.api.CreateFrame( "Button", "TurtleMailOpenMailButton", inbox, "UIPanelButtonTemplate" ) m.api.TurtleMailOpenMailButton = button + created = true 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) ) + local parent_changed = false + if button.GetParent and button.SetParent then + if button:GetParent() ~= inbox then + button:SetParent( inbox ) + parent_changed = true + end + elseif created and button.SetParent then + button:SetParent( inbox ) + parent_changed = true 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 + local needs_anchor = created or parent_changed + if not needs_anchor and button.GetPoint then + local point, relative_to, relative_point, x, y = button:GetPoint() + needs_anchor = point ~= "BOTTOM" + or (relative_to and relative_to ~= inbox) + or relative_point ~= "BOTTOM" + or x ~= -10 + or y ~= 90 + end + + if needs_anchor then + if button.ClearAllPoints then button:ClearAllPoints() end + button:SetPoint( "BOTTOM", inbox, "BOTTOM", -10, 90 ) + end + + local wanted_text = m.api.OPENMAIL or "Open Mail" + local text_changed = created + if button.GetText then + text_changed = button:GetText() ~= wanted_text + end + if text_changed and button.SetText then + button:SetText( wanted_text ) + end + + -- Recalculate dimensions only when the button was created or its label changed. + if created or text_changed then + 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 + end + + if button.SetScript then + local onclick = button.GetScript and button:GetScript( "OnClick" ) or nil + if created or onclick ~= m.inbox_open_all then + button:SetScript( "OnClick", m.inbox_open_all ) + end + end if inbox.GetFrameLevel and button.SetFrameLevel then - button:SetFrameLevel( (inbox:GetFrameLevel() or 0) + 5 ) + local target_level = (inbox:GetFrameLevel() or 0) + 5 + local current_level = button.GetFrameLevel and button:GetFrameLevel() or nil + if current_level ~= target_level then + button:SetFrameLevel( target_level ) + end end - if button.Enable then button:Enable() end - if button.Show then button:Show() end + if button.Enable then + if not button.IsEnabled or not button:IsEnabled() then + button:Enable() + end + end + if button.Show then + if not button.IsShown or not button:IsShown() then + button:Show() + end + end return button end @@ -530,8 +582,6 @@ 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