Invalidate event (Repaint) can be starved with long executing actions

Bug #857123 reported by ciplogic
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Pinta
New
Undecided
Unassigned

Bug Description

In PintaCanvas (Pinta.Gui.Widgets/Widgets/Canvas/PintaCanvas.cs) is the processing of messages.

In the worst casse scenario, like a took that is occurring many times and in itself that it take a lot of time, i.e. gradient on a big picture, the painting of the control occurs very late.

Steps to reproduce:
- Create a new picture of 3000x3000 or any size that gradient will happen slow
- Move mouse many seconds around making gradient to be seen

Actual result:
- after releasing the mouse button, Pinta will do in the background painting of the gradients and will look like frozen

Expected result:
- just the last gradient should be executed, all "intermediary" invisible gradients should not be processed

Note: to test this behavior:
- add in Linux build Console.Writeline("Start time: {0}". Environment.TickCount); at the start of OnMouseMvove from GradientTool, end of OnMouseMove add Console.Writeline("Start time: {0}". Environment.TickCount);,and in PintaCanvas.cs at the OnExposeEvent add another Console.WriteLine("Paint the widget");

Revision history for this message
ciplogic (ciprian-mustiata) wrote :

I attached a patch that may address the problem (certainly fixes on my machine, I don't know side effects on other actions).

In short the fixes are:
 Added an internal class (could be added to Utility class, as was added RangeEnumerator) that can store just one computation, and made one internal instance to compute that:
       ToCompute _toCompute = new ToCompute();
         class ToCompute
        {
            public delegate void ExecutedEvent();
            public ExecutedEvent Executed;

            public void AddEvent(ExecutedEvent ev)
            {
                Executed = null;
                 Executed += ev;
            }

            public void ComputeAll()
            {
                if(Executed!=null)
                    Executed();
                Executed = null;
             }
        }

Add the MotionEvents with AddEvent that will clear the previous motion event and will take all closures arguments using lambdas:
So previous code was:
MotionNotifyEvent += delegate (object sender, MotionNotifyEventArgs e) {
                 if (!PintaCore.Workspace.HasOpenDocuments)
And it was replaced with:
MotionNotifyEvent += delegate (object sender, MotionNotifyEventArgs e) {
                _toCompute.AddEvent( () => { //here is the lambda
                 if (!PintaCore.Workspace.HasOpenDocuments)
and after that is forcing a view paint:
               }; //end of lambda
                GdkWindow.Invalidate();

And at last, but not at least, added the motion event in invalidate method at start of it:
 So the previous code:

            base.OnExposeEvent (e);

            if (!PintaCore.Workspace.HasOpenDocuments)
                return true;

was replaced with:

            base.OnExposeEvent (e);

            _toCompute.ComputeAll();

            if (!PintaCore.Workspace.HasOpenDocuments)
                return true;

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.