@bobfrankston/rmfmail 1.2.245 → 1.2.247

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/mailx.js CHANGED
@@ -2925,12 +2925,67 @@ RFC 5322 with CRLF line endings. Bodies are quoted-printable encoded (readable i
2925
2925
  // moment to bring rmfmail forward, replacing the old per-save focus grab.
2926
2926
  imapManager.on("wordEditClosed", (payload) => {
2927
2927
  handle.send({ _event: "wordEditClosed", type: "wordEditClosed", ...payload });
2928
- // Only raise the MAIN window when the compose lives IN it. A popout
2929
- // compose is a separate window with no service channel, so focusing
2930
- // main would just cover it up.
2931
- if (!payload.fromPopout)
2928
+ // Coming back from Word, the window you were editing has to be the one
2929
+ // in front otherwise the edit lands in a window buried behind
2930
+ // whatever Word was covering (Bob 2026-08-10).
2931
+ //
2932
+ // In-window compose: raise the main window through the service pipe,
2933
+ // which msger consumes natively (msger 0.1.407).
2934
+ if (!payload.popoutId) {
2932
2935
  handle.send({ _msgerWindow: "focus" });
2936
+ return;
2937
+ }
2938
+ // Popout compose: a separate OS window. msger's MessageBoxHandle
2939
+ // exposes result/pid/close and no control channel — its stdin is
2940
+ // closed right after the options are written — so there is nothing to
2941
+ // send a focus command to. Raise it by process instead. Windows-only
2942
+ // and deliberately so: this is the same platform-gated corner as the
2943
+ // Word autosave sidecar, and Edit-in-Word is a Windows/Mac feature.
2944
+ // A msger-side focus() would be the tidier home for this and is worth
2945
+ // doing when msger is next opened.
2946
+ const h = popoutWindows.get(`compose|${payload.popoutId}`);
2947
+ const pid = h?.pid;
2948
+ if (!pid) {
2949
+ console.log(` [word-edit] popout ${payload.popoutId} has no live window to raise`);
2950
+ return;
2951
+ }
2952
+ if (process.platform !== "win32")
2953
+ return;
2954
+ void raiseWindowByPid(pid);
2933
2955
  });
2956
+ /** Bring the main window of a process to the foreground (Windows).
2957
+ * Uses the documented AllowSetForegroundWindow → SetForegroundWindow
2958
+ * dance rather than a bare SetForegroundWindow, which Windows ignores
2959
+ * for a process that does not own the foreground — the same reason
2960
+ * msger's own focusOnCreate does it that way. Best-effort: a failure
2961
+ * leaves the window where it is and is logged, never thrown. */
2962
+ async function raiseWindowByPid(pid) {
2963
+ const ps = [
2964
+ "$ErrorActionPreference='Stop'",
2965
+ "Add-Type @'",
2966
+ "using System;using System.Runtime.InteropServices;",
2967
+ "public class RmfFg{",
2968
+ "[DllImport(\"user32.dll\")] public static extern bool SetForegroundWindow(IntPtr h);",
2969
+ "[DllImport(\"user32.dll\")] public static extern bool ShowWindow(IntPtr h,int c);",
2970
+ "[DllImport(\"user32.dll\")] public static extern bool AllowSetForegroundWindow(int p);",
2971
+ "}",
2972
+ "'@",
2973
+ `$p = Get-Process -Id ${pid} -ErrorAction SilentlyContinue`,
2974
+ "if ($p -and $p.MainWindowHandle -ne 0) {",
2975
+ ` [RmfFg]::AllowSetForegroundWindow(${pid}) | Out-Null`,
2976
+ " [RmfFg]::ShowWindow($p.MainWindowHandle, 9) | Out-Null", // SW_RESTORE
2977
+ " [RmfFg]::SetForegroundWindow($p.MainWindowHandle) | Out-Null",
2978
+ "}",
2979
+ ].join("\n");
2980
+ try {
2981
+ const { spawn } = await import("node:child_process");
2982
+ const child = spawn("powershell", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", ps], { detached: false, stdio: "ignore", windowsHide: true });
2983
+ child.on("error", (e) => console.log(` [word-edit] could not raise compose window: ${e?.message || e}`));
2984
+ }
2985
+ catch (e) {
2986
+ console.log(` [word-edit] raise failed: ${e?.message || e}`);
2987
+ }
2988
+ }
2934
2989
  // Cloud-write/read failures from mailx-settings → push to UI as a banner so
2935
2990
  // silent fall-back-to-local can no longer swallow Drive errors.
2936
2991
  const { onCloudError } = await import("@bobfrankston/mailx-settings");