Merge lp://qastaging/~mc-return/compiz/compiz.merge-fix1165198-horizontally-semimaximized-windows-do-not-snap-off-easily into lp://qastaging/compiz/0.9.10

Proposed by MC Return
Status: Merged
Approved by: Sam Spilsbury
Approved revision: 3650
Merged at revision: 3654
Proposed branch: lp://qastaging/~mc-return/compiz/compiz.merge-fix1165198-horizontally-semimaximized-windows-do-not-snap-off-easily
Merge into: lp://qastaging/compiz/0.9.10
Diff against target: 658 lines (+207/-181)
3 files modified
plugins/move/move.xml.in (+31/-10)
plugins/move/src/move.cpp (+169/-166)
plugins/move/src/move.h (+7/-5)
To merge this branch: bzr merge lp://qastaging/~mc-return/compiz/compiz.merge-fix1165198-horizontally-semimaximized-windows-do-not-snap-off-easily
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Sam Spilsbury Approve
MC Return Pending
Review via email: mp+158508@code.qastaging.launchpad.net

This proposal supersedes a proposal from 2013-04-08.

Commit message

*Move xml:

Implemented options to configure:

"Snapoff Distance"
"Snapback Semimaximized Windows" and
"Snapback Distance"

Improved a few tooltips.

*Move code:

Replaced SNAP_BACK and SNAP_OFF hardcoded constants and made those
configurable.

Implemented a strategy to snap off horizontally maximized windows by
dragging them along the x axis.

Implemented snapping back of horizontally maximized windows and fixed
the snapping for vertically maximized windows (wrong cursor calculation).

Fixed a few wrong calculations in the if condition checks responsible
for snapping off and back.

Merged if condition checks.

Just compute various local variables if we do not return false.

Removed redundant brackets, fixed indentation and improved readability.

(LP: #1165198, LP: #1167933)

Description of the change

[How to reproduce]

1.Semi-maximize a window horizontally (right mousebutton-click on the maximize button)
2.Try to restore your window by dragging the title bar to the side.

[What you would expect to happen]

The window should restore after you've dragged the titlebar a few pixels to the side.

[What actually happens]

The window will not restore until you reach the side of the screen and trigger either
a viewport switch or trigger the grid preview.

The problem is hidden in static void moveHandleMotionEvent (CompScreen *s, int xRoot, int yRoot)

if (ms->optionGetSnapoffMaximized ()) does not check if (w->state () & (CompWindowStateMaximizedHorzMask)

Here you can find a low quality screencast demonstrating this MP:
https://bugs.launchpad.net/compiz/+bug/1167933/+attachment/3642013/+files/Screencast-showing-move-fixes-and-upgrade.vob

To post a comment you must log in.
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

128 + int x = wX + dx - w->border ().left;
129 + int y = wY + dy - w->border ().top;
130 + int width = wWidth + w->border ().left + w->border ().right;
131 + int height = w->border ().top ? w->border ().top : 1;
132 +
133 + int status = XRectInRegion (ms->region, x, y,
134 + (unsigned int) width,
135 + (unsigned int) height);

Can you align wX, wY, wWidth and w->border (), they've become de-aligned.

+ CompRect workArea = s->getWorkareaForOutput (w->outputDevice ());

This is better written as

CompRect workArea (s->getWorkareaForOutput (w->outputDevice ());

153 + if (w->saveMask ()& CWWidth)

You'll need a space between w->saveMask () and "&"

159 + ms->x = ms->y = 0;
160 +

Will that cause the window to be moved back to 0,0 ? I haven't got time to check at the moment.

Revision history for this message
MC Return (mc-return) wrote : Posted in a previous version of this proposal

> 128 + int x = wX + dx - w->border ().left;
> 129 + int y = wY + dy - w->border ().top;
> 130 + int width = wWidth + w->border ().left +
> w->border ().right;
> 131 + int height = w->border ().top ? w->border ().top :
> 1;
> 132 +
> 133 + int status = XRectInRegion (ms->region, x, y,
> 134 + (unsigned int) width,
> 135 + (unsigned int)
> height);
>
> Can you align wX, wY, wWidth and w->border (), they've become de-aligned.
>
Done.

> + CompRect workArea = s->getWorkareaForOutput (w->outputDevice ());
>
> This is better written as
>
> CompRect workArea (s->getWorkareaForOutput (w->outputDevice ());
>
Done.

> 153 + if (w->saveMask ()& CWWidth)
>
> You'll need a space between w->saveMask () and "&"
>
Done.

> 159 + ms->x = ms->y = 0;
> 160 +
>
> Will that cause the window to be moved back to 0,0 ? I haven't got time to
> check at the moment.
>

Effect is that the center of the window's titlebar gets moved to the mousepointer,
when it snaps off, no matter where the mousepointer is...
This behaviour is identical no matter if using Emerald and gtk-window-decorator.

So behaviour is quite okay as the user mostly pulls off the window somewhere along
the titlebar, it can feel a bit jumpy if the user decides to pull the window off by
pulling the left corner, but this is another problem for another day...
(the same happens when pulling off vertically maxed windows in trunk)

So this MP just imitates the successful method for pulling off vertically maximized
windows by using x instead of y.

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Actually, now that I've looked at this in context, I can see why it is correct, but probably in need of some refactoring.

    if (w->state () & CompWindowStateMaximizedVertMask)
    {
        if (abs (yRoot - workArea.y () - ms->snapOffY) >= SNAP_OFF)
       if (!s->otherGrabExist ("move", NULL))
       {
         int width = w->serverGeometry ().width ();

         w->saveMask () |= CWX | CWY;

         if (w->saveMask () & CWWidth)
                width = w->saveWc ().width;

         w->saveWc ().x = xRoot - (width >> 1);
         w->saveWc ().y = yRoot + (w->border ().top >> 1);

         ms->x = ms->y = 0;

         w->maximize (0);

         ms->snapOffY = ms->snapBackY;

         return;
       }
    }
    else if (w->state () & CompWindowStateMaximizedHorzMask)
    {
        if (abs (xRoot - workArea.x () - ms->snapOffX) >= SNAP_OFF)
       if (!s->otherGrabExist ("move", NULL))
       {
         int width = w->serverGeometry ().width ();

         w->saveMask () |= CWX | CWY;

         if (w->saveMask () & CWWidth)
                width = w->saveWc ().width;

         w->saveWc ().x = xRoot - (width >> 1);
         w->saveWc ().y = yRoot + (w->border ().top >> 1);

         ms->x = ms->y = 0;

         w->maximize (0);

         ms->snapOffX = ms->snapBackX;

         return;
       }
    }

What the code will do in both cases is set the restore position such that the window is under the pointer upon restore, and then restore the window. Its effectively eight lines of repeated code, and could probably just be refactored into a separate function called "restoreWindowToCursorCentralTitlebarPosition"

Revision history for this message
MC Return (mc-return) wrote : Posted in a previous version of this proposal

> Actually, now that I've looked at this in context, I can see why it is
> correct, but probably in need of some refactoring.
>
> if (w->state () & CompWindowStateMaximizedVertMask)
> {
> if (abs (yRoot - workArea.y () - ms->snapOffY) >= SNAP_OFF)
> if (!s->otherGrabExist ("move", NULL))
> {
> int width = w->serverGeometry ().width ();
>
> w->saveMask () |= CWX | CWY;
>
> if (w->saveMask () & CWWidth)
> width = w->saveWc ().width;
>
> w->saveWc ().x = xRoot - (width >> 1);
> w->saveWc ().y = yRoot + (w->border ().top >> 1);
>
> ms->x = ms->y = 0;
>
> w->maximize (0);
>
> ms->snapOffY = ms->snapBackY;
>
> return;
> }
> }
> else if (w->state () & CompWindowStateMaximizedHorzMask)
> {
> if (abs (xRoot - workArea.x () - ms->snapOffX) >= SNAP_OFF)
> if (!s->otherGrabExist ("move", NULL))
> {
> int width = w->serverGeometry ().width ();
>
> w->saveMask () |= CWX | CWY;
>
> if (w->saveMask () & CWWidth)
> width = w->saveWc ().width;
>
> w->saveWc ().x = xRoot - (width >> 1);
> w->saveWc ().y = yRoot + (w->border ().top >> 1);
>
> ms->x = ms->y = 0;
>
> w->maximize (0);
>
> ms->snapOffX = ms->snapBackX;
>
> return;
> }
> }
>
> What the code will do in both cases is set the restore position such that the
> window is under the pointer upon restore, and then restore the window. Its
> effectively eight lines of repeated code, and could probably just be
> refactored into a separate function called
> "restoreWindowToCursorCentralTitlebarPosition"

Yes, agreed. I'll see what I can do to reduce this code duplication.

Revision history for this message
MC Return (mc-return) wrote : Posted in a previous version of this proposal

>
> What the code will do in both cases is set the restore position such that the
> window is under the pointer upon restore, and then restore the window. Its
> effectively eight lines of repeated code, and could probably just be
> refactored into a separate function called
> "restoreWindowToCursorCentralTitlebarPosition"

This might take a while as I've already found a ton of stuff in this code, that
could be improved and optimized.
The good thing is -> the move code is short :)

Examples:
There are a ton of

if (a)
    if (b)
        if (c)
        {
            do ()
        }

combinations, or things like:

 if (s->otherGrabExist ("move", NULL))
     return false;

 if (ms->w)
     return false;

 if (w->type () & (CompWindowTypeDesktopMask |
         CompWindowTypeDockMask |
         CompWindowTypeFullscreenMask))
     return false;

 if (w->overrideRedirect ())
     return false;

which can be better written as:

 if (s->otherGrabExist ("move", NULL) ||
     ms->w ||
     w->overrideRedirect () ||
     w->type () & (CompWindowTypeDesktopMask |
     CompWindowTypeDockMask |
     CompWindowTypeFullscreenMask))
     return false;

also this block above comes after these lines:

 unsigned int mods = CompOption::getIntOptionNamed (options, "modifiers", 0);

 int x = CompOption::getIntOptionNamed (options, "x", w->geometry ().x () +
            (w->size ().width () / 2));
 int y = CompOption::getIntOptionNamed (options, "y", w->geometry ().y () +
            (w->size ().height () / 2));

 int button = CompOption::getIntOptionNamed (options, "button", -1);

but all those calculations of local variables do not need to happen if we return false, so
those should be calculated after the return false check...

Also I noticed that we have a SNAP_BACK strategy for vertically maximized windows, but
none for horz maxed ones...
I have to see what it exactly does and if we still need that. From flying over the code it
seems to be responsible for snapping back into the vert maxed position it was snapped of from
if the mousepointer has not been released in the meantime, but I could be wrong...

Not even looked at moving stuff to separate functions yet as cleanup reveals a lot of potential
for optimization...

Revision history for this message
MC Return (mc-return) wrote : Posted in a previous version of this proposal

For the sake of a smaller diff size and easier review, I propose that this could be merged first, so I can build up from this version...

review: Needs Information
Revision history for this message
MC Return (mc-return) wrote : Posted in a previous version of this proposal

Okay, further investigation shows that the SNAP_BACK code has some purpose -
it is the one I speculated about above...

TODO: Although snapping back horizontally maxed windows does not make that much sense,
      it should be implemented as well to harmonize snap off/snap back behaviour of
      those window types...

TODO: SNAP_BACK and SNAP_OFF are constants, but should ideally be configurable also
      (distance in pixels, the mouse has to travel to snap off/snap back).

Revision history for this message
MC Return (mc-return) wrote : Posted in a previous version of this proposal

> Okay, further investigation shows that the SNAP_BACK code has some purpose -
> it is the one I speculated about above...
>
> TODO: Although snapping back horizontally maxed windows does not make that
> much sense,
> it should be implemented as well to harmonize snap off/snap back
> behaviour of
> those window types...
>
Done (in local branch).

> TODO: SNAP_BACK and SNAP_OFF are constants, but should ideally be configurable
> also
> (distance in pixels, the mouse has to travel to snap off/snap back).

Done (in local branch).

@Sam: There will be a new MP hopefully soonish. Got almost all move problems
      figured out now (finally)...
      The back-snapping of horizontally maxed wins still makes (very minor)
      problems - should work for left & right sides IMHO...
      In my local branch I made backsnapping configurable as well :)
      This is how it currently looks:
      http://uppix.net/1/1/e/06bbae1c05a85dc86ea0870b52ead.png

Revision history for this message
MC Return (mc-return) wrote : Posted in a previous version of this proposal

A few comments:

It is not perfect.
There was a ton of stuff broken, wrongly calculated and such.
This is now all fixed, but small problems (only snap-back) remain:

1. I implemented snapping back horizontal windows, but it will just work for the left side of your screen for now.

2. I corrected the mousepointer-coordinates when snapping back vertically resized windows and warping the pointer works there, but this function does not like to work with horizontally maxed wins :(
Although I have the correct coordinates, the timing somehow fails to work... but this is a rather minor issues and I've even implemented the possibility to turn off the backsnapping...

Revision history for this message
MC Return (mc-return) wrote :
Revision history for this message
Sam Spilsbury (smspillaz) wrote :

This is mostly fine now.

Can you remove this commented out code?

404 + if (abs (xRoot - workArea.x () - ms->snapBackX) < snapbackDistance) /* ||
405 + abs (workArea.width () - workArea.x () - xRoot) < snapbackDistance) */
406 + {
...
410 + // s->warpPointer (workArea.width () / 2 - snapbackDistance, 0);

Revision history for this message
MC Return (mc-return) wrote :

> This is mostly fine now.
>
> Can you remove this commented out code?
>
> 404 + if (abs (xRoot - workArea.x () - ms->snapBackX) <
> snapbackDistance) /* ||
> 405 + abs (workArea.width () - workArea.x () -
> xRoot) < snapbackDistance) */
> 406 + {
> ...
> 410 + // s->warpPointer (workArea.width () / 2 -
> snapbackDistance, 0);

I kept this code, because it contains the correct calculation already:

/* ||
> 405 + abs (workArea.width () - workArea.x () -
> xRoot) < snapbackDistance) */

is the right side of the screen (for horizontal snapback).

and:

// s->warpPointer (workArea.width () / 2 - snapbackDistance, 0);

is the correct horizontal warping of the mousepointer when snapping back.

Unfortunately I had troubles, because for some unknown reason the horizontal
warp will interrupt the resizing (horizontal maximizing).

But I'll put this in a comment...
You are ofc. right: Does not look best that way :)

3650. By MC Return

Removed commented out code and added TODO comments instead

Revision history for this message
MC Return (mc-return) wrote :

> This is mostly fine now.
>
> Can you remove this commented out code?
>
Done in r3650.
I have replaced it with TODO comments. Hope it is better now :)

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

Yep, all good.

review: Approve
Revision history for this message
MC Return (mc-return) wrote :

> Yep, all good.

:)

Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
The diff is not available at this time. You can reload the page or download it.

Subscribers

People subscribed via source and target branches

to all changes: