Repaint issue with XShm drawings


#1

Sometimes, when the interface is repainted, I see parts of the gui being painted at the wrong place. It seems to happen most often when two disjoint parts of the interface are invalidated at the same time. This is caused by the shmCompletedDrawing flag not taking into account that in these situations , there is more than one XShmPutImage in flight at a given time. In order to make sure that the LinuxRepaintManager does never proceed until all XShmPutImage have completed, that I suggest to replace that flag by a counter. It fixes all my repaints issues:

[code]@@ -1776,17 +1782,18 @@
class LinuxRepaintManager : public Timer
{
public:
LinuxRepaintManager (LinuxComponentPeer* const peer_)
: peer (peer_),
lastTimeImageUsed (0)
{
#if JUCE_USE_XSHM

  •        shmCompletedDrawing = true;
    
  •        shmDrawingInProgress = 0;
    
           useARGBImagesForRendering = XSHMHelpers::isShmAvailable();
    
           if (useARGBImagesForRendering)
           {
               ScopedXLock xlock;
               XShmSegmentInfo segmentinfo;
    

@@ -1798,17 +1805,17 @@
XDestroyImage (testImage);
}
#endif
}

     void timerCallback()
     {
        #if JUCE_USE_XSHM
  •        if (! shmCompletedDrawing)
    
  •        if (shmDrawingInProgress)
               return;
          #endif
           if (! regionsNeedingRepaint.isEmpty())
           {
               stopTimer();
               performAnyPendingRepaintsNow();
           }
           else if (Time::getApproximateMillisecondCounter() > lastTimeImageUsed + 3000)
    

@@ -1824,17 +1831,17 @@
startTimer (repaintTimerPeriod);

         regionsNeedingRepaint.add (area);
     }

     void performAnyPendingRepaintsNow()
     {
        #if JUCE_USE_XSHM
  •      if (! shmCompletedDrawing)
    
  •      if (shmDrawingInProgress) 
           {
               startTimer (repaintTimerPeriod);
               return;
           }
          #endif
    
           peer->clearMaskedRegion();
    

@@ -1873,47 +1880,55 @@
ScopedPointer context (peer->getComponent().getLookAndFeel()
.createGraphicsContext (image, -totalArea.getPosition(), adjustedList));
peer->handlePaint (*context);
}

             if (! peer->maskedRegion.isEmpty())
                 originalRepaintRegion.subtract (peer->maskedRegion);

+#if JUCE_USE_XSHM

  •               shmDrawingInProgress = 0;
    

+#endif
for (const Rectangle* i = originalRepaintRegion.begin(), * const e = originalRepaintRegion.end(); i != e; ++i)
{
#if JUCE_USE_XSHM

  •                shmCompletedDrawing = false;
    
  •                shmDrawingInProgress++;
                 #endif
    
                   static_cast<XBitmapImage*> (image.getPixelData())
                       ->blitToWindow (peer->windowH,
                                       i->getX(), i->getY(), i->getWidth(), i->getHeight(),
                                       i->getX() - totalArea.getX(), i->getY() - totalArea.getY());
               }
           }
    
           lastTimeImageUsed = Time::getApproximateMillisecondCounter();
           startTimer (repaintTimerPeriod);
       }
    
      #if JUCE_USE_XSHM
    
  •    void notifyPaintCompleted()                 { shmCompletedDrawing = true; }
    
  •    void notifyPaintCompleted()                 { 
    
  •           shmDrawingInProgress--;
    
  •    }
      #endif
    

    private:
    enum { repaintTimerPeriod = 1000 / 100 };

       LinuxComponentPeer* const peer;
       Image image;
       uint32 lastTimeImageUsed;
       RectangleList regionsNeedingRepaint;
    
      #if JUCE_USE_XSHM
    
  •    bool useARGBImagesForRendering, shmCompletedDrawing;
    
  •    bool useARGBImagesForRendering;
    
  •    int shmDrawingInProgress;
      #endif
       JUCE_DECLARE_NON_COPYABLE (LinuxRepaintManager)
    

    };

    ScopedPointer repainter;

    friend class LinuxRepaintManager;
    Window windowH, parentWindow;

[/code]


#2

Ah, good call, thanks!