When using inline mode IME typing word, save point state is toggled for each tentative added character, which may cause undesired behavior in host app, such as flash on title bar, like https://github.com/zufuliu/notepad2/issues/203 (reproducible with SciTE).
for win32 case, in ScintillaWin::HandleCompositionInline(), pdoc->TentativeUndo() leads to NotifySavePoint(true)/SCN_SAVEPOINTREACHED; InsertCharacter() leads to Document::InsertString(), then NotifySavePoint(false)/SCN_SAVEPOINTLEFT.
I revoke the patch.
sorry! misunderstood.
Here is the workaround I currently use:
Is it already fixed?
Try it without your patch.
There's a comment on https://github.com/zufuliu/notepad2/issues/203 :
If the change can cause the application to not know that the document is saved/unsaved then its too dangerous.
My patch relies on
GCS_COMPSTRcallInsertCharacter(), however from the code it's not always true, then application will in a dirty state.It seems reasonable that pendingUpdate be renamed to IsCompStrExist.
You apply !pendingUpdate
so NotifySavePoint(endSavePoint) always is performed
only when !IsCompStrExist.
That is, while in composition No NotifySavePoint except for empty compStr.
some word contains
composition(e.g.startComposition) might be thanIsCompStrExist.sorry! Test to be required patch attached
Composing 'ㅎ'
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:::NotifySavePoint:::
Composing '하'
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:::NotifySavePoint:::
Composing '한'
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:::NotifySavePoint:::
Composing '한ㄱ'
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:::NotifySavePoint:::
Composing '한그'
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:::NotifySavePoint:::
Composing '한글'
-----------------------Commit :'한글'----------------------
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:::NotifySavePoint:::
-----------------------Commit :' '----------------------
Composing 'ㅁ'
tentativeSteps: -1, startSavePoint: 0, endSavePoint: 0
Composing '마'
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 0
Composing '만'
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 0
Composing '만ㅅ'
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 0
Composing '만세'
-----------------------Commit :'만세'----------------------
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 0
-----------------------Commit :' '----------------------
It turns out NotifySavePoint() never be performed except for initial TentativeUndo.
It seems Ok to Remove NotifySavePoint() from TentativeUndo().
initial TentativeUndo() compStr should not influence on title bar since that is tentative and should be treated none.
No, please test other IMEs (e.g. MS Pinyin) and continue type letters, the composition string will continue to grow, each letter will cause TentativeUndo + InsertCharacter.
I use SciTEGtk to test this.
Is this something different?
--- preeditStr:'w' ---
savePoint: 0, currentAction: 0
savePoint: 0, currentAction: 2
savePoint: 0, currentAction: 0
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:Tentative NotifySavePoint:
--- preeditStr:'wo' ---
savePoint: 0, currentAction: 0
savePoint: 0, currentAction: 2
savePoint: 0, currentAction: 3
savePoint: 0, currentAction: 0
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:Tentative NotifySavePoint:
--- preeditStr:'wo a' ---
savePoint: 0, currentAction: 0
savePoint: 0, currentAction: 2
savePoint: 0, currentAction: 3
savePoint: 0, currentAction: 4
savePoint: 0, currentAction: 5
savePoint: 0, currentAction: 0
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:Tentative NotifySavePoint:
--- preeditStr:'wo ai' ---
savePoint: 0, currentAction: 0
savePoint: 0, currentAction: 2
savePoint: 0, currentAction: 3
savePoint: 0, currentAction: 4
savePoint: 0, currentAction: 5
savePoint: 0, currentAction: 6
savePoint: 0, currentAction: 0
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:Tentative NotifySavePoint:
--- preeditStr:'wo ai n' ---
savePoint: 0, currentAction: 0
savePoint: 0, currentAction: 2
savePoint: 0, currentAction: 3
savePoint: 0, currentAction: 4
savePoint: 0, currentAction: 5
savePoint: 0, currentAction: 6
savePoint: 0, currentAction: 7
savePoint: 0, currentAction: 8
savePoint: 0, currentAction: 0
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:Tentative NotifySavePoint:
--- preeditStr:'wo ai ni' ---
savePoint: 0, currentAction: 0
savePoint: 0, currentAction: 2
savePoint: 0, currentAction: 3
savePoint: 0, currentAction: 4
savePoint: 0, currentAction: 5
savePoint: 0, currentAction: 6
savePoint: 0, currentAction: 7
savePoint: 0, currentAction: 8
--- CommitStr :'我爱你'----
savePoint: 0, currentAction: 9
savePoint: 0, currentAction: 0
tentativeSteps: 0, startSavePoint: 0, endSavePoint: 1
:Tentative NotifySavePoint:
savePoint: 0, currentAction: 0
savePoint: 0, currentAction: 2
savePoint: 0, currentAction: 3
--- CommitStr :'a'----
savePoint: 0, currentAction: 4
--- CommitStr :'b'----
savePoint: 0, currentAction: 5
--- CommitStr :'c'----
savePoint: 0, currentAction: 6
savePoint: 0, currentAction: 7
savePoint: 0, currentAction: 0
tentativeSteps: -1, startSP: 0, endSP: 1
:Ctrl+Z Undo NotifySavePoint:
Tested again on Win 10, indeed only first (when document unmodified) compositing has the behavior (save point change on each tentative added character). if document is already modified no save point change is notified.
do not redraw while TentativeActive as redrawPendingText.
patch proposed
NotifySavePoint() in TentativeUndo() is needed at least when press Esc key to cancel.
So I follow your idea redrawPendingText.
I got another idea for this: delay
NotifySavePoint()to the end ofScintillaWin::HandleCompositionInline().pseudo code:
Delaying to the end of
HandleCompositionInlinewould avoid the title flash but it may conflict with application logic that closely follows events.The application could implement a coalescing mechanism similar to window invalidation & painting. When the app receives a
SCN_SAVEPOINTREACHEDorSCN_SAVEPOINTLEFT, it posts itself an 'update title' message. When it receives an 'update title' it callsSetWindowNameto update. Since the 'update title' won't be received until all the changes caused byHandleCompositionInlinehave finished, it won't display the temporary state.It seems delayed idea can be used to fix dirty state bug in my workaround: tells
TentativeUndo()that current composition string is likely to be replaced with new composition string, and save the changed save point. at end ofHandleCompositionInline()if the replacement does not actually happen, then notify the saved save point.pseudo code:
A potential problem is that the application won't be receiving the save-point notifications at the time when it can examine the state of the document that corresponds to that save-point.
The motivating 'title asterisk flash' problem does not appear important enough to break compatibility with previous behaviour.
If completely pushing the issue to application code is too much then there could be an intermediate approach where
Notification::UpdateUIis used to deliver a newUpdate::SavePointasynchronously. An application may then choose whether to respond toNotification::SavePointReached/Notification::SavePointLeftor toUpdate::SavePointor to a combination such as setting the dirty flag inNotification::SavePoint*and updating the title inUpdate::SavePoint.Patch that implements
TentativeSavePoint, the save point will only be notified/delayed when current composition string not been replaced with new composition string or composition result (GCS_RESULTSTRalso cause toggled states), e.g. when press Esc. This can treated as modelHandleCompositionInline()as a string replace operation, and drop the tentative save point when operating succeeded .it can be used for other platforms in a simple way:
Still need to dig more, as it seems better to fire
NotifySavePoint()with zero once (just like direct input) instead of for each tentative character.Notepad2 switched to delay save point approach:
https://github.com/zufuliu/notepad2/commit/e10af5ffcd7103c047f01ea155413cdf5f5ed37c
This reduce inline mode IME save point notification (to application) to just 2:
NotifySavePoint(0)on start andNotifySavePoint(1)on cancel, none on typing more tentative characters, whereas window mode IME there is onlyNotifySavePoint(0)on complete. Maybe an option ("disable inline IME tentative save point change notification during compositing"?) can be added to enable this experimental workaround if application think it's OK for them.Have you checked whether this will work if there is a save during IME entry? Saves may be performed automatically on a timer in some applications.
Shouldn't have
~DelaySavePointcall non-noexceptmethod.