From 4db9163a7d544d30f80d3654bd2c12f64946803f Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Fri, 24 Apr 2026 16:39:36 +0200 Subject: [PATCH] arm: LimitNotifyEvents around the four paste sites --- plans/ARM64_Flicker_Analysis.md | 295 ++++++++++++++++++++++++++++++++ src/Edit.c | 2 + src/Notepad3.c | 8 + 3 files changed, 305 insertions(+) create mode 100644 plans/ARM64_Flicker_Analysis.md diff --git a/plans/ARM64_Flicker_Analysis.md b/plans/ARM64_Flicker_Analysis.md new file mode 100644 index 000000000..60bdcacbf --- /dev/null +++ b/plans/ARM64_Flicker_Analysis.md @@ -0,0 +1,295 @@ +# ARM64 Flicker Analysis — Notepad3 Editor Pane + +**Scope:** Slow, visible flicker in the Scintilla editor pane on Qualcomm ARM64 devices, strongly correlated with paste operations, aggravated by Windows 11 25H2, behaving differently across GDI vs. D2D rendering. A recent ARM64 mitigation reduced but did not eliminate the problem. + +**Date:** 2026-04-24 +**Repository state:** branch `dev_master`, tip `d6d5f41b5` + +--- + +## 1. Problem statement + +- Affects: Notepad3 on Windows-on-ARM (Snapdragon / Qualcomm Adreno GPUs). +- Trigger: most visible during copy/paste into the editor pane; also reported on theme / DPI / color-scheme transitions. +- OS sensitivity: worse on Windows 11 25H2 than on 23H2/24H2. +- Rendering-mode sensitivity: flicker pattern differs between GDI (`SC_TECHNOLOGY_DEFAULT`) and D2D variants. +- After the recent ARM64 fix: reduced but still present. + +--- + +## 2. What the recent ARM64 fix actually does + +Two application-level changes (no Scintilla patches were needed for the fix itself): + +| Change | Location | Effect | +|---|---|---| +| Main window carries `WS_EX_COMPOSITED` on ARM64 only | `src/Notepad3.c:1914-1918` | DWM double-buffers the parent bottom-up. | +| Default `RenderingTechnology = SC_TECHNOLOGY_DIRECTWRITERETAIN` (2) on ARM64 | `src/Config/Config.cpp:1332-1338` | Scintilla uses a GDI-compatible retained `ID2D1DCRenderTarget` instead of a DXGI flip swap chain. | + +Pre-existing and unchanged by that fix: + +- The **status bar also has `WS_EX_COMPOSITED`** unconditionally (`src/Notepad3.c:3314-3323`). On ARM64 this means the paint path now has **nested** composited surfaces (main + status). +- `scintilla/np3_patches/upstream_558/001_undo_selection_redraw.patch` adds an extra `Redraw()` after undo-selection restore — relevant because paste is an undoable action. + +--- + +## 3. Cause model — why paste specifically, why 25H2, why Adreno + +A paste is not a single repaint; it is a **storm of paint triggers** arriving in the same few milliseconds, coinciding with a DWM state that Adreno/25H2 handles poorly: + +1. `SciCall_Paste()` modifies many lines atomically → Scintilla issues at least one full-visible-range `Redraw()`. +2. `SCN_MODIFIED` fires → `EnableDocChangeNotification()` (`src/Notepad3.c:374-381`) calls `EditUpdateVisibleIndicators()` → additional margin / marker invalidates. +3. The same callback calls `UpdateStatusbar(false)`. This is deferred via a timer, but the deferred path at `src/Notepad3.c:10818-10833` does: + + ```c + SendMessage(Globals.hwndStatus, WM_SETREDRAW, FALSE, 0); + // ... SB_SETPARTS / SB_SETMINHEIGHT / StatusSetText ... + SendMessage(Globals.hwndStatus, WM_SETREDRAW, TRUE, 0); + InvalidateRect(Globals.hwndStatus, NULL, TRUE); // note TRUE + ``` + +4. `SCN_UPDATEUI` fires → caret / selection repaint + status update. +5. Auto-scroll into view if the caret moves below the visible region → another full pane invalidate. +6. If the paste lands inside an active "mark all occurrences" region, `MarkAllOccurrences` queues and fires shortly after. +7. On undo, the patched `Redraw()` from `upstream_558/001` fires again. + +On Intel/AMD + recent Win11 builds, DWM collapses this into ~1 frame. On **Adreno + 25H2**, DWM appears to present the parent composited buffer and Scintilla's own D2D surface on *different ticks*, exposing the composited buffer (background colour) between Scintilla's `BeginDraw`/`EndDraw` pairs. `DIRECTWRITERETAIN` reduces this because the retained target keeps the previous frame visible across the gap — but if the parent composited buffer is invalidated by a secondary update (status bar) mid-burst, a flash is still visible. + +**Why the GDI vs. D2D behaviour differs:** + +| Mode | Mechanism | Interaction with `WS_EX_COMPOSITED` | +|---|---|---| +| `SC_TECHNOLOGY_DEFAULT` (0, GDI) | No swap chain; WM_PAINT-driven | Parent composition mostly wins; flicker is background-erase-driven. | +| `SC_TECHNOLOGY_DIRECTWRITE` (1) | DXGI swap chain on Scintilla's HWND | Scintilla presents independently of DWM compositor → heavy flicker on Adreno/25H2. | +| `SC_TECHNOLOGY_DIRECTWRITERETAIN` (2) | GDI-compatible D2D; retained target | Current ARM64 default; compromise — presented via GDI on WM_PAINT. | +| `SC_TECHNOLOGY_DIRECTWRITEDC` (3) | `ID2D1DCRenderTarget` over a DC from WM_PAINT | Fully parented into GDI; `WS_EX_COMPOSITED` can buffer the result end-to-end. | + +--- + +## 4. Remaining suspects, ranked by likelihood + +### A. Status-bar invalidation with `bErase = TRUE` during paste bursts — **high suspicion** + +`src/Notepad3.c:10833`: + +```c +InvalidateRect(Globals.hwndStatus, NULL, TRUE); +``` + +The status bar is `SBT_OWNERDRAW | WS_EX_COMPOSITED`. Passing `TRUE` forces a `WM_ERASEBKGND` cycle on a window that owner-draws its own background — wasted work that also invalidates the parent composited buffer. Every paste triggers this path. Matches the paste-coupling pattern exactly. + +### B. Nested `WS_EX_COMPOSITED` (main + status bar) — **medium-high suspicion** + +Main window on ARM64 and the status bar (always) both carry `WS_EX_COMPOSITED`. DWM documentation warns against combining `WS_EX_COMPOSITED` with child windows that do their own buffered rendering; having **two layers** of compositor-buffering along the paint path is a known problematic combination on newer DWM builds. The status-bar flag predates the ARM64 fix and wasn't revisited when the parent flag was added. + +### C. `SC_TECHNOLOGY_DIRECTWRITERETAIN` is a half-measure — **medium suspicion** + +Mode 2 uses `ID2D1DCRenderTarget` + the retain-usage bit but still presents via GDI on WM_PAINT, with its own back buffer. Mode 3 (`DIRECTWRITEDC`) hands the DC from the HWND's WM_PAINT straight through, which is what `WS_EX_COMPOSITED` expects. On some 25H2 builds the retained target fails to be invalidated between paste-triggered paints, leaving a stale tile that the next paint flashes over. Would explain "helped a bit, still flickers". + +### D. `MsgThemeChanged` uses `RDW_ERASE | RDW_ALLCHILDREN` — **low-medium suspicion** + +`src/Notepad3.c:3478`: + +```c +RedrawWindow(hwnd, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); +``` + +Correct for a theme change, but `MsgDPIChanged` re-invokes `MsgThemeChanged`, and 25H2 has been observed to fire spurious DPI / colour-scheme change messages more eagerly (dark mode toggles, accent changes, HDR transitions). Note the contradiction with `src/DarkMode/ListViewUtil.hpp:64`, which deliberately omits `RDW_ERASE` for exactly this reason — the main-window path is the outlier. Relevant only if the user reports flicker on non-paste events too. + +### E. `LimitNotifyEvents` / `RestoreNotifyEvents` is not used around paste — **medium suspicion** + +`src/Notepad3.h:182` defines a macro that suppresses `SCN_*` notifications and toggles `WM_SETREDRAW` on the edit window. It is used for bulk edits (sort, encode, etc.) — but **paste uses `UndoTransActionBegin` only**, which groups undo but does nothing for notification throttling. Each inserted chunk can still trigger a full notify / repaint cycle. Especially relevant for paste of large clipboard contents. + +### F. `SciCall_SetBufferedDraw` is never called — **low suspicion** + +Declared at `src/SciCall.h:166-167` but never invoked. In GDI mode and `DIRECTWRITEDC` mode this flag enables Scintilla's own offscreen bitmap buffering; under D2D modes 1 and 2 Scintilla ignores it. Relevant only when experimenting with `DIRECTWRITEDC`. + +--- + +## 5. Recommended experiments (ordered, cheapest first) + +Each step isolates one hypothesis. Validate with the reporter after each. + +1. **Flip the status-bar erase flag.** Change `InvalidateRect(Globals.hwndStatus, NULL, TRUE)` → `FALSE` at `src/Notepad3.c:10833`. Zero risk (owner-drawn control paints its own background). Targets suspect **A**. +2. **Remove `WS_EX_COMPOSITED` from the status bar on ARM64** (or everywhere). Targets suspect **B**. If flicker worsens on non-ARM64, revert; on ARM64 with the parent already composited, the status-bar flag is almost certainly redundant. +3. **Ask the reporter to set `RenderingTechnology=3` (`DIRECTWRITEDC`) in their INI.** Single-line INI change, no rebuild needed. If it fixes flicker, make it the ARM64 default (targets suspect **C**). If it worsens paste flicker, keep mode 2 and move on. +4. **Wrap the paste path in `LimitNotifyEvents` / `RestoreNotifyEvents`** (targets suspect **E**): + + ```c + case IDM_EDIT_PASTE: + if (SciCall_CanPaste()) { + if (s_flagPasteBoard) { s_bLastCopyFromMe = true; } + LimitNotifyEvents(); + UndoTransActionBegin(); + SciCall_Paste(); + EndUndoTransAction(); + RestoreNotifyEvents(); + } + break; + ``` + + The macro already toggles `WM_SETREDRAW` on `Globals.hwndEdit` and invalidates once at the end. This collapses the paste burst into a single repaint — directly targeting the paste-specific complaint. + +5. **Audit `_DelayUpdateStatusbar` throttle interval for ARM64.** If ≤16 ms, multiple fires occur inside a single frame; ~50 ms during paste bursts is safer. +6. **Long term:** introduce a `Settings2.ARM64FlickerWorkaround` umbrella flag bundling whichever of (1)–(4) prove necessary, so end-users on affected hardware can opt in without a rebuild. (Document per repo convention: `Build/Notepad3.ini` commented entry + prose in `readme/config/Configuration.md`.) + +--- + +## 6. What not to do + +- **Don't add `WM_ERASEBKGND` handlers.** The architecture deliberately relies on OS + Scintilla painting; intercepting becomes a maintenance rabbit hole. +- **Don't drop `WS_EX_COMPOSITED` from the main window on ARM64 without a replacement.** It is doing real work; the problem is the downstream invalidation traffic, not the flag itself. +- **Don't add `DwmFlush()` calls.** Tempting but wrong — serializes against DWM at significant cost and typically hides the symptom rather than fixing it. + +--- + +## 7. Bottom line + +The dominant remaining contributor is almost certainly a **paste-driven cascade of secondary invalidations** (status bar with `bErase=TRUE`, double-composited surfaces, un-throttled `SCN_*` notifications) interacting with an already-fragile DWM path on Adreno + 25H2. The recent ARM64 fix (`WS_EX_COMPOSITED` + `DIRECTWRITERETAIN`) addressed the *Scintilla* side; what remains is the **peripheral paint traffic around each paste** that the parent composited buffer has to keep up with. + +Cheapest first move: change the `TRUE` erase flag at `src/Notepad3.c:10833` to `FALSE`, and wrap `IDM_EDIT_PASTE` in `LimitNotifyEvents` / `RestoreNotifyEvents`. Those two together are ~5 lines and target the two most load-bearing suspects. + +--- + +## Appendix A — Key files and line references + +| Concern | File | Line(s) | +|---|---|---| +| ARM64 `WS_EX_COMPOSITED` on main window | `src/Notepad3.c` | 1914-1918 | +| ARM64 default render technology | `src/Config/Config.cpp` | 1332-1338 | +| Render-tech applied to Scintilla | `src/Notepad3.c` | 2578-2579 | +| Render-tech runtime switch | `src/Notepad3.c` | 6701-6708 | +| Render-tech INI load | `src/Config/Config.cpp` | 1826 | +| `MsgThemeChanged` | `src/Notepad3.c` | 3432-3484 | +| Status-bar creation (WS_EX_COMPOSITED) | `src/Notepad3.c` | 3314-3323 | +| Status-bar update (erase TRUE) | `src/Notepad3.c` | 10818-10833 | +| `IDM_EDIT_PASTE` handler | `src/Notepad3.c` | 5222-5231 | +| `UndoTransActionBegin` / `EndUndoTransAction` | `src/Notepad3.h` | 188-189 | +| `LimitNotifyEvents` / `RestoreNotifyEvents` | `src/Notepad3.h` | 182 | +| `EnableDocChangeNotification` (post-modify callback) | `src/Notepad3.c` | 374-381 | +| DarkMode redraw without `RDW_ERASE` | `src/DarkMode/ListViewUtil.hpp` | 64, 126 | +| Undo-selection Redraw patch | `scintilla/np3_patches/upstream_558/001_undo_selection_redraw.patch` | — | + +## Appendix B — Scintilla rendering technology constants + +| Constant | Value | Underlying target | Swap model | +|---|---|---|---| +| `SC_TECHNOLOGY_DEFAULT` | 0 | GDI | `WM_PAINT` BitBlt | +| `SC_TECHNOLOGY_DIRECTWRITE` | 1 | DXGI flip swap chain | Independent present | +| `SC_TECHNOLOGY_DIRECTWRITERETAIN` | 2 | `ID2D1DCRenderTarget` + retain | Via GDI on `WM_PAINT` | +| `SC_TECHNOLOGY_DIRECTWRITEDC` | 3 | `ID2D1DCRenderTarget` on caller DC | Via `WM_PAINT` DC | + +--- + +## Appendix C — `SciCall_SetBufferedDraw` deep-dive + +Follow-up investigation: could suspect F (Scintilla's own buffered-draw flag) be a useful ARM64-only lever? Answer: **no, not a promising path**. Detailed reasoning below, grounded in the vendored Scintilla sources under `scintilla/`. + +### C.1 What the flag does + +**Default value:** `true`, set in `EditView::EditView()` at `scintilla/src/EditView.cxx:186`. + +**Upstream comment** (`scintilla/src/EditView.h:60-62`): + +> "In bufferedDraw mode, graphics operations are drawn to a pixmap and then copied to the screen. This avoids flashing but is about 30% slower." + +**Mechanism (GDI path):** when on, Scintilla allocates two persistent pixmaps per view (`Editor.cxx:1861-1866`): + +- `pixmapLine` — width of the client area, height of one line +- `pixmapSelMargin` — fixed-column width, full client height + +In the paint loop, each line is drawn into `pixmapLine` and then `BitBlt`-ed onto the window DC (`EditView.cxx:2490-2614`, `SurfaceGDI.cxx:638-644`). When off, Scintilla draws directly to the window DC under an explicit `SetClip`/`PopClip` (`Editor.cxx:1910-1957`). + +### C.2 The auto-override that kills this lever + +Every `SCI_SETTECHNOLOGY` handler (`scintilla/win32/ScintillaWin.cxx:2280-2308`) forcibly assigns: + +```cpp +view.bufferedDraw = technologyNew == Technology::Default; +``` + +Practical consequence: + +| `SetTechnology` argument | `bufferedDraw` becomes | +|---|---| +| `SC_TECHNOLOGY_DEFAULT` (0, GDI) | `true` | +| `SC_TECHNOLOGY_DIRECTWRITE` (1) | `false` | +| `SC_TECHNOLOGY_DIRECTWRITERETAIN` (2) — **ARM64 default** | `false` | +| `SC_TECHNOLOGY_DIRECTWRITEDC` (3) | `false` | + +So any `SciCall_SetBufferedDraw(true)` we emit must come **after** `SciCall_SetTechnology`, and must be re-applied on every runtime tech switch (`Notepad3.c:6701-6708`), every `MsgThemeChanged`, and every `MsgDPIChanged` (the latter re-enters `MsgThemeChanged`). + +### C.3 Benefits + +- **GDI mode (0):** real benefit — per-line pixmap isolation reduces intra-line flicker. But already on by default, so Notepad3 does not need to touch it. +- **D2D modes (1, 2, 3, 4):** the flag is technically wired (`SurfaceD2D::Copy` uses `pRenderTarget->DrawBitmap`, `SurfaceD2D.cxx:989-1000`), so forcing it on would allocate per-line D2D bitmap render targets. Functionally works, but adds a stage to the pipeline rather than eliminating one. +- **None of these targets the actual ARM64 failure mode** (DWM compositor present misalignment between the parent composited buffer and Scintilla's D2D surface). + +### C.4 Disadvantages + +- **~30% slower paint** (upstream's own number). +- **Extra GDI handles / D2D bitmaps** — two persistent pixmaps held per view, reallocated on every resize, tech change, or `DropGraphics()`. +- **Silently clobbered** by every `SetTechnology` call — fragile to maintain. +- **Adds a third buffer stage on ARM64.** Main window already has `WS_EX_COMPOSITED` (parent composited buffer) and Scintilla has its retained D2D target. Inserting a per-line Scintilla pixmap makes three stages of buffering competing for GPU bandwidth — plausibly worse on Adreno, not better. +- **`WM_ERASEBKGND` is already suppressed** inside Scintilla's own wndproc (`ScintillaWin.cxx:2472-2473: return 1`), so the classical "avoid background flash" benefit is already paid for without this flag. + +### C.5 Would ARM-gating `SciCall_SetBufferedDraw(true)` help? + +Almost certainly not: + +1. ARM64 default is `DIRECTWRITERETAIN`. Scintilla auto-disables `bufferedDraw` when that tech is set. Without re-applying after every `SetTechnology`, the call is a no-op. +2. The reported symptom is compositor-present misalignment, not per-line paint cadence. Buffered draw operates at the paint-cadence layer and cannot influence DWM composition ordering. +3. Adding a third buffer layer increases GPU work on a platform whose GPU/compositor pipeline is the root bottleneck. + +### C.6 Verdict + +Not pursued. The flag is a pre-DWM GDI-era flicker mitigation; it does not reach the layer where the ARM64 + 25H2 + Adreno symptom actually lives. Leverage points B and C remain the right next moves and are pursued in the code changes dated 2026-04-24. + +### C.7 Key references + +| Concern | File | Line(s) | +|---|---|---| +| `bufferedDraw` default = `true` | `scintilla/src/EditView.cxx` | 186 | +| Auto-override on `SCI_SETTECHNOLOGY` | `scintilla/win32/ScintillaWin.cxx` | 2303 | +| Pixmap allocation | `scintilla/src/Editor.cxx` | 1861-1866 | +| GDI `BitBlt` copy | `scintilla/win32/SurfaceGDI.cxx` | 638-644 | +| D2D `DrawBitmap` copy | `scintilla/win32/SurfaceD2D.cxx` | 989-1000 | +| Clip branches on flag | `scintilla/src/Editor.cxx` | 1910-1957 | +| Scintilla swallows `WM_ERASEBKGND` | `scintilla/win32/ScintillaWin.cxx` | 2472-2473 | + +--- + +## Appendix D — Applied changes from leverage points B and E (2026-04-24) + +After shipping leverage points A (status-bar erase flag) and the initial E wrap on `IDM_EDIT_PASTE`, the remaining paste sites and leverage point B were applied. Leverage point C was prepared but then reverted — see Appendix E. + +**Leverage point B — un-nest `WS_EX_COMPOSITED` on ARM64** (`src/Notepad3.c:3314-3327`). The status bar drops its own `WS_EX_COMPOSITED` on ARM64 only; on that platform the main window already composites its children bottom-up, so the status bar's own flag only created a nested compositor stage. Non-ARM64 platforms retain the existing flag unchanged. + +**Leverage point E extended — `LimitNotifyEvents` / `RestoreNotifyEvents` around all four `SciCall_Paste()` sites.** Same pattern as the earlier `IDM_EDIT_PASTE` change: collapse the `SCN_MODIFIED` / `SCN_UPDATEUI` burst into one end-of-paste invalidate. Scope matches the existing `UndoTransActionBegin` / `EndUndoTransAction` block exactly at each site; no wider refactoring. + +| Site | File:Line | Trigger | +|---|---|---| +| `IDM_EDIT_PASTE` | `src/Notepad3.c:5233-5237` | Menu / Ctrl+V (shipped earlier) | +| `EditSwapClipboard()` | `src/Edit.c:936-954` | `IDM_EDIT_SWAP` | +| New-from-clipboard at startup | `src/Notepad3.c:2140-2148` | `/c` command-line flag | +| `PasteBoardTimerProc()` | `src/Notepad3.c:12464-12499` | `/B` pasteboard-monitor mode, each clipboard change | + +All four sites retain their `UndoTransActionBegin`/`EndUndoTransAction` undo grouping unchanged; the new macros wrap around the existing undo wrap. + +--- + +## Appendix E — Leverage point C not applied as a default change (2026-04-24) + +**Decision:** the ARM64 default rendering technology stays at `SC_TECHNOLOGY_DIRECTWRITERETAIN` (2). A brief switch to `SC_TECHNOLOGY_DIRECTWRITEDC` (3) was reverted on the same day. + +**Rationale:** + +1. The original recommendation in section 5 was to test mode 3 **as an INI-side experiment first**, then only promote it to default if the reporter confirmed improvement. Flipping the default without that validation skipped the decision gate. +2. Project preference is to stay on D2D rendering paths. Although mode 3 still uses DirectWrite for glyph rendering, its presentation path (`ID2D1DCRenderTarget` blitting via GDI on `WM_PAINT`) is GDI-composed at the final stage. This is closer in character to the GDI mode (0) that is considered "not usable" than to modes 1 and 2, which use proper D2D render targets. +3. `DIRECTWRITERETAIN` (2) remains the best compromise among the D2D-only options: it keeps the retained back buffer that mitigates the Adreno + 25H2 compositor misalignment, without routing the final stage through GDI. + +**What this means for further investigation:** + +- Mode 3 is *not* promoted to default. +- It may still be tested ad-hoc by individual users via INI (`RenderingTechnology=3`) without a rebuild. +- Next ARM64 levers to try while staying on D2D: the three deferred `SciCall_Paste` wrapping sites (`EditSwapClipboard` at `src/Edit.c:943,946`, startup `/c` at `src/Notepad3.c:2144`, `PasteBoardTimerProc` at `src/Notepad3.c:12488`); and possibly raising the clamp at `Config.cpp:1329` to expose `SC_TECHNOLOGY_DIRECT_WRITE_1` (4) as an experimental option. diff --git a/src/Edit.c b/src/Edit.c index f37a359dc..f5c60cbc3 100644 --- a/src/Edit.c +++ b/src/Edit.c @@ -933,6 +933,7 @@ bool EditSwapClipboard(HWND hwnd, bool bSkipUnicodeCheck) DocPos const iCurPos = SciCall_GetCurrentPos(); DocPos const iAnchorPos = SciCall_GetAnchor(); + LimitNotifyEvents(); UndoTransActionBegin(); char* pszText = NULL; @@ -950,6 +951,7 @@ bool EditSwapClipboard(HWND hwnd, bool bSkipUnicodeCheck) pszText = NULL; EndUndoTransAction(); + RestoreNotifyEvents(); if (!Sci_IsMultiOrRectangleSelection()) { //~UndoTransActionBegin(); diff --git a/src/Notepad3.c b/src/Notepad3.c index f725ebb12..4ca33a5cf 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -2137,6 +2137,7 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow) bool bAutoIndent2 = Settings.AutoIndent; Settings.AutoIndent = 0; EditJumpTo(-1, 0); + LimitNotifyEvents(); UndoTransActionBegin(); if (!Sci_IsDocEmpty()) { SciCall_NewLine(); @@ -2144,6 +2145,7 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow) SciCall_Paste(); SciCall_NewLine(); EndUndoTransAction(); + RestoreNotifyEvents(); Settings.AutoIndent = bAutoIndent2; if (s_flagJumpTo) { SciCall_SetYCaretPolicy(s_iCaretPolicyV | CARET_JUMPS, Settings2.CurrentLineVerticalSlop); @@ -3312,7 +3314,11 @@ void CreateBars(HWND hwnd, HINSTANCE hInstance) //~Globals.hwndStatus = CreateStatusWindow(dwStatusbarStyle, NULL, hwnd, IDC_STATUSBAR); Globals.hwndStatus = CreateWindowEx( +#if defined(_M_ARM64) + 0, // parent already has WS_EX_COMPOSITED on ARM64; avoid nested compositor stage +#else WS_EX_COMPOSITED, // => double-buffering avoids flickering +#endif STATUSCLASSNAME, // name of status bar class (PCTSTR)NULL, // no text when first created dwStatusbarStyle, // creates a visible child window @@ -12455,6 +12461,7 @@ void CALLBACK PasteBoardTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD if (SciCall_CanPaste()) { bool bAutoIndent2 = Settings.AutoIndent; Settings.AutoIndent = 0; + LimitNotifyEvents(); UndoTransActionBegin(); // Paste at the current caret position. Pre-pend the configured @@ -12489,6 +12496,7 @@ void CALLBACK PasteBoardTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD } SciCall_Paste(); EndUndoTransAction(); + RestoreNotifyEvents(); Sci_ScrollSelectionToView(); Settings.AutoIndent = bAutoIndent2; s_dwLastPasteSeqNo = dwCurrentSeqNo;