Bug 326243 - StyledText receives unneeded and malformed Paint events
Summary: StyledText receives unneeded and malformed Paint events
Status: CLOSED WONTFIX
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 3.7   Edit
Hardware: Macintosh Mac OS X
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Platform-SWT-Inbox CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords: triaged
Depends on:
Blocks:
 
Reported: 2010-09-25 17:33 EDT by Doug M CLA
Modified: 2020-03-01 05:40 EST (History)
2 users (show)

See Also:


Attachments
Example of the problems (2.96 KB, application/octet-stream)
2010-09-25 17:33 EDT, Doug M CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Doug M CLA 2010-09-25 17:33:25 EDT
Created attachment 179576 [details]
Example of the problems

Please run the provided example. It displays two StyledText  areas and one Text area directly in a Shell. All have PaintListeners. When a Paint event is received, its contents are logged and the paintable area's background is painted a different color. It also plops a red X across some of the foreground text.

It appears to me that certain Paint events are not needed, or contain incorrect information. If my interpretation is wrong, I am glad to be corrected. The context is a desktop client that decorates and annotates text areas using the Paint event, an expensive operation. When incorrect Paint events are sent, they degrade responsiveness.

1) Drag the window's resize corner to make it larger. Paint events are sent to redraw the entire contents of all three text areas. Since those text areas are not in any way affected by the resize of the parent (nothing is revealed, resized, or moved), I think no Paint events should be sent. Certainly in this example as in my application, neither the text areas nor its decorations should be redrawn when the parent window is resized without affecting its content.


2) Take a look at the Paint events generated by the flashing caret.

a. Are these events necessary at all? I thought that the OS itself can handle saving and restoring the bits under a blinking caret. Would you consider implementing this way to eliminate this continuous stream of events and the objects they create?

b. Given that the caret is implemented by drawing over the Widget content, I understand that a Paint event is needed when the caret blinks away. But StyledText sends an event when the caret is both drawn and hidden. No Paint event is needed when it is drawn. In fact, drawing during this caret drawn event seems to have no effect. (If it did, the red X would appear opaque.) 

Check out the Text area: an event is sent there only after the caret is hidden. I think this is the correct behavior.

c. Please consider a flag that distinguishes caret flash Paint events from all others. I am willing to tolerate a small damage to an annotation while the caret is blinking inside it in exchange for lower resource consumption.

d. The time stamp in the caret flash events does not change. See debugger console. That's why I am numbering the events in the output.

3) Comment in the return statement that causes caret updates (width 1) to be ignored. Now move the cursor around the StyledText area using mouse or arrow keys. You will see Paint events generated, apparently whenever the caret is moved while it was visible. But you also see the Paint area (and clipping rectangle) are not width 1 but larger, maybe a character width. In any case, drawing into this rectangle ONLY draws over the old caret position. (Otherwise you would see the Paint rectangle become a different background color.) It is also clear, by running the cursor over the 'X', that StyledText itself is not redrawing this larger rectangle, so no update of the whole Paint area was ever actually required. 

The issue here is that the Paint rectangle is wrong, which eliminates my only kludge for distinguishing caret-generated damage. Note that the Text area does not generate these malformed Paint events.

Thanks for your attention to these issues.

SWT 3.7M1/OS 10.6.4
Comment 1 Silenio Quarti CLA 2010-09-28 15:16:13 EDT
These are interesting points. I am not sure we can do much about some of them, but we need more investigation. Here are my initial thoughts:

1) SWT sends paint events when cocoa calls NSView.drawRect(). SWT does not have any control when that happens and it cannot determine if the paint events are necessary or not. I suspect that these paint events are coming because cocoa implements the "Painters" algorithm.  Given that Text (native widget) has the same behavior, I believe any cocoa application would have it.

2.a) I would not consider implementing caret blinking this way. It is usually the source of pixel corruption.  Even Text (native widget) does not implement it that way.

2.b) In order to cause damage only when the caret is hidden, SWT would have to draw the caret outside the cocoa paint cycle (Painters algorithm). This would require the code to clip against all siblings/children obscuring the caret rectangle. It is doable, but it is time consuming. Put a canvas above the Text widget, give focus to the widget so that the caret is under the canvas and you will see what I mean.


        Canvas canvas = new Canvas(shell, SWT.NONE);
        canvas.setBackground(display.getSystemColor(SWT.COLOR_RED));
        canvas.moveAbove(text1);
        canvas.setBounds(18, 258, 30, 30);


2.c) The flag does not make sense for at least two reasons: 1- the other platforms (Windows, GTK) do not implement caret blinking by damaging the widget. It would be only available in the Mac.  2. It cannot be implemented because damage in cocoa is done by calling setNeedsDisplayInRect() which does not call NSView.drawRect() right away. By the time, NSView.drawRect() is called there is no way to determine that only the caret damage is the cause of that call. There could be other outstanding damage that gets merged in one call (see below 3)).

2.d) Yes, this is a problem. Paint is not an event in cocoa, so it does not generate a timestamp. The timestamp SWT provides is the timestamp of the last key/mouse event handled.

3. This is happening because two (or more) damage rectangles caused by the caret drawing implementation are merged by cocoa into one call to NSView.drawRect() with the union rectangle as the damage. That is why if you move the care with ARROW_LEFT quickly, the damage rectangle has the width of one character some times.

I suspect that this does not happen in Text (native widget) because Text calls NSView.display() (or NSView.displayRect() ) after calling setNeedsDisplayInRect() to redraw the caret.   Letting the damage rectangles get merged is usually the right thing to do.   We need to investigate further to determine if calling NSView.display() after damaging the caret rectangle makes sense.
Comment 2 Lakshmi P Shanmugam CLA 2017-07-03 08:40:16 EDT
Bug triaged, visit https://wiki.eclipse.org/SWT/Devel/Triage for more
information.
Comment 3 Eclipse Genie CLA 2020-03-01 05:40:38 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. As such, we're closing this bug.

If you have further information on the current state of the bug, please add it and reopen this bug. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.