Avoiding jumps when moving non-native windows


#1

Hi Jules,

When I drag a juce window (jucedemo for example) with a non-native titlebar, it jumps randomly (that is if I drag it slowly from left to right, it jumps to the left and to the right). This happens on unity, I don’t know if it happens on other setups.

Looking at handleMotionNotifyEvent function , I noticed that commenting the ‘updateBounds()’ just fixes all that strange behaviour , and now when dragging the window, it is not jumpy anymore. I also don’t understand the purpose of the call to XQueryTree in that function , why not replacing all of this with just ‘parentWindow = movedEvent.window’

[code]— a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp
+++ b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp
@@ -1519,48 +1519,29 @@ public:
void handleMotionNotifyEvent (const XPointerMovedEvent& movedEvent)
{
updateKeyModifiers (movedEvent.state);
const Point mousePos (movedEvent.x_root, movedEvent.y_root);

     if (lastMousePos != mousePos)
     {
         lastMousePos = mousePos;

         if (parentWindow != 0 && (styleFlags & windowHasTitleBar) == 0)
         {
  •            Window wRoot = 0, wParent = 0;
    
  •            {
    
  •                ScopedXLock xlock;
    
  •                unsigned int numChildren;
    
  •                Window* wChild = nullptr;
    
  •                XQueryTree (display, windowH, &wRoot, &wParent, &wChild, &numChildren);
    
  •            }
    
  •            if (wParent != 0
    
  •                 && wParent != windowH
    
  •                 && wParent != wRoot)
    
  •            {
    
  •                parentWindow = wParent;
    
  •                updateBounds();
    
  •            }
    
  •            else
    
  •            {
    
  •                parentWindow = 0;
    
  •            }
    
  •           parentWindow = movedEvent.window;
           }
    
           if (dragState.dragging)
               handleExternalDragMotionNotify();
    
  •        handleMouseEvent (0, mousePos - getScreenPosition(), currentModifiers, getEventTime (movedEvent));
    
  •        handleMouseEvent (0, getMousePos(movedEvent), currentModifiers, getEventTime (movedEvent));
       }
    
    }
    [/code]

(maybe there was a reason for writing the call to handleMouseEvent with mousePos - getScreenPosition ? I don’t know, but all other event handlers are using getMousePos(event))

Everything seems to work as expected in JuceDemo after this change.


#2

Damn, I wish I could remember why that stuff was in there, because it must have had some purpose… It looks like it’s just there to work out the x, y position based on the root_x, root_y rather than the x, y values, but there’s no reason to think that x, y would be wrong… It may just be some hacky code left over from the very early days of the library that never got tidied-up.

I’ve refactored it a bit now - have a go and let me know how you get on.


#3

Have you pushed your changes ? I see nothing new in the git repository


#4

Yes, it’s up there.


#5

Got it, it seems to work perfectly fine !


#6

Hi Jules,

I think I found why updateBounds was called in handleMotionNotify. When the window is embedded in another parent windows (editor window of a vst plugin for example, embedded in a host window), the LinuxPeerComponent does not get any notifications when one of its parents is moved on the screen. So its X and Y absolute screen coordinates stored in the ‘bounds’ variable are not updated. Everything works fine, except the buttons that do not repond to clicks anymore.

It does not seem to be useful to call updateBounds every time the mouse is moved (and that would bring back the bug that this thread was attempting to fix), so what I suggest to do is to put a call to updateBounds at the beginning of handleEnterNotifyEvent :

[code] void handleEnterNotifyEvent (const XEnterWindowEvent& enterEvent)
{

  •    if (parentWindow) // absolute screen coords of this window must be brought up to date in case the parent has been moved
    
  •        updateBounds();
       clearLastMousePos();
    
       if (! currentModifiers.isAnyMouseButtonDown())
    

[/code]

It seems to work fine: no strange jumps when dragging a juce window, and buttons of the vst plugin do repond to clicks.


#7

Ah yes, I knew there was a reason!

Ok… although the idea of only updating on a mouse-enter doesn’t sound good to me. Perhaps on a mouse-up as well?


#8

Yes, why not, it should not interfere with windows dragging


#9

I was playing with the new -fsanitize=address option of gcc 4.8 and it immediately found a bug in that code ! When selecting an entry in a submenu, the handleMouseEvent call in handleButtonReleaseEvent triggers the destruction of the LinuxComponentPeer, hence the if (parentWindow != 0) updateBounds(); that is performed just after is incorrect since (*this) is now an object that has been destroyed. So I suggest to put it at the top of the function.


#10

gotcha.

Haven’t tried -fsanitize=address yet, but it sounds handy.