Bug 129423 - Active borders (electric borders) warp the mouse too much
Summary: Active borders (electric borders) warp the mouse too much
Status: RESOLVED FIXED
Alias: None
Product: kwin
Classification: Plasma
Component: general (show other bugs)
Version: unspecified
Platform: Debian testing Linux
: NOR normal
Target Milestone: ---
Assignee: KWin default assignee
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-06-19 14:24 UTC by Hrvoje Niksic
Modified: 2007-06-21 17:07 UTC (History)
0 users

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Hrvoje Niksic 2006-06-19 14:24:44 UTC
Version:            (using KDE KDE 3.5.3)
Installed from:    Debian testing/unstable Packages

kwin's active borders push the mouse not to the beginning of next desktop, but to about 200 pixels off the screen edge.  For example, on a 1024x768 screen, if you move your mouse to the far right, after switching the desktop, the pointer won't be on the left side of the screen, but ~200 pixels from the left side.

At first, this sounds like a feature, possibly designed to prevent flicker of changing desktops in case the user's mouse drifts a pixel or two back and forth.  However, upon some consideration, it doesn't seem like such a good idea:

1. It breaks the conceptual idea that desktops form a seamless whole.  The push of the mouse of 1/5th of the screen is disconcerting.

2. It makes it way harder to reach screen edges.  If you need to hit a position near the edge of the screen, an accidental switch warps you much far away (both conceptually and effectively) from the edge of the adjacent screen.  Instead of correcting the accidental switch by moving the mouse back by the same amount, you have to move it additional 200 pixels to re-reach the edge.  And when you get back to the previous desktop, the mouse is *again* warped 200 pixels off the edge.  That means that a two-pixel mistake requires a 402 pixel correction.  Any user interface book will tell you that hitting a precise point is harder when your hand has to travel a large distance, and this is exactly what the 200-pixel push is forcing you to do.  :-(

3. There is already an effective way of preventing accidental desktop switches: the resistance configuration.

As far as I can tell, the warp is implemented in Workspace::clientMoved.  I propose to remove the offset feature (currently 1/5th of the screen) or to make it configurable.  In the latter case the configuration doesn't need to be part of the GUI, but it would be nice to have at least *some* way to turn it off.

Ideally it should just be turned off by default.
Comment 1 Lubos Lunak 2007-06-15 15:06:21 UTC
SVN commit 675918 by lunakl:

Allow also diagonal desktop switching with electric borders.
Don't warp the mouse so much after the switch.

BUG: 81170
BUG: 129423



 M  +35 -56    workspace.cpp  


--- trunk/KDE/kdebase/workspace/kwin/workspace.cpp #675917:675918
@@ -2225,20 +2225,13 @@
 
 void Workspace::reserveElectricBorderSwitching( bool reserve )
     {
-    if( reserve )
-        {
-        reserveElectricBorder( ElectricTop );
-        reserveElectricBorder( ElectricBottom );
-        reserveElectricBorder( ElectricLeft );
-        reserveElectricBorder( ElectricRight );
-        }
-    else
-        {
-        unreserveElectricBorder( ElectricTop );
-        unreserveElectricBorder( ElectricBottom );
-        unreserveElectricBorder( ElectricLeft );
-        unreserveElectricBorder( ElectricRight );
-        }
+    for( int pos = 0;
+         pos < ELECTRIC_COUNT;
+         ++pos )
+        if( reserve )
+            reserveElectricBorder( static_cast< ElectricBorder >( pos ));
+        else
+            unreserveElectricBorder( static_cast< ElectricBorder >( pos ));
     }
 
 void Workspace::reserveElectricBorder( ElectricBorder border )
@@ -2328,54 +2321,40 @@
 
     // reset the pointer to find out wether the user is really pushing
     // (the direction back from which it came, starting from top clockwise)
-    static int xdiff[ ELECTRIC_COUNT ] = { 0, -1, -1, -1, 0, 1, 1, 1 };
-    static int ydiff[ ELECTRIC_COUNT ] = { 1, 1, 0, -1, -1, -1, 0, 1 };
+    const int xdiff[ ELECTRIC_COUNT ] = { 0, -1, -1, -1, 0, 1, 1, 1 };
+    const int ydiff[ ELECTRIC_COUNT ] = { 1, 1, 0, -1, -1, -1, 0, 1 };
     QCursor::setPos( pos.x() + xdiff[ border ], pos.y() + ydiff[ border ] );
     }
 
-void Workspace::electricBorderSwitchDesktop( ElectricBorder border, const QPoint& pos )
+void Workspace::electricBorderSwitchDesktop( ElectricBorder border, const QPoint& _pos )
     {
-    QRect r = QApplication::desktop()->geometry();
-    int offset;
-
-    int desk_before = currentDesktop();
-    switch(border)
+    QPoint pos = _pos;
+    int desk = currentDesktop();
+    const int OFFSET = 10;
+    if( border == ElectricLeft || border == ElectricTopLeft || border == ElectricBottomLeft )
         {
-        case ElectricLeft:
-            slotSwitchDesktopLeft();
-            if (currentDesktop() != desk_before)
-                {
-                offset = r.width() / 5;
-                QCursor::setPos(r.width() - offset, pos.y());
-                }
-            break;
-        case ElectricRight:
-            slotSwitchDesktopRight();
-            if (currentDesktop() != desk_before)
-                {
-                offset = r.width() / 5;
-                QCursor::setPos(offset, pos.y());
-                }
-            break;
-        case ElectricTop:
-            slotSwitchDesktopUp();
-            if (currentDesktop() != desk_before)
-                {
-                offset = r.height() / 5;
-                QCursor::setPos(pos.x(), r.height() - offset);
-                }
-            break;
-        case ElectricBottom:
-            slotSwitchDesktopDown();
-            if (currentDesktop() != desk_before)
-                {
-                offset = r.height() / 5;
-                QCursor::setPos(pos.x(), offset);
-                }
-            break;
-        default:
-            break;
+        desk = desktopToLeft( desk );
+        pos.setX( displayWidth() - 1 - OFFSET );
         }
+    if( border == ElectricRight || border == ElectricTopRight || border == ElectricBottomRight )
+        {
+        desk = desktopToRight( desk );
+        pos.setX( OFFSET );
+        }
+    if( border == ElectricTop || border == ElectricTopLeft || border == ElectricTopRight )
+        {
+        desk = desktopUp( desk );
+        pos.setY( displayHeight() - 1 - OFFSET );
+        }
+    if( border == ElectricBottom || border == ElectricBottomLeft || border == ElectricBottomRight )
+        {
+        desk = desktopDown( desk );
+        pos.setY( OFFSET );
+        }
+    int desk_before = currentDesktop();
+    setCurrentDesktop( desk );
+    if( currentDesktop() != desk_before )
+        QCursor::setPos( pos ); 
     }
 
 // this function is called when the user entered an electric border
Comment 2 Hrvoje Niksic 2007-06-18 15:07:05 UTC
Would it be possible to customize (and perhaps completely remove) the hard-coded OFFSET constant?  As explained above in point #2, the offset makes it that much harder to pinpoint the mouse to a location near the edge of the screen because an inadvertent switch to the adjacent desktop makes the mouse OFFSET*2 pixels away from the target[1].  With small targets this is a problem.


[1]
It's OFFSET*2 rather than just OFFSET because the mouse is first warped OFFSET pixels after the inadvertent switch, and then OFFSET more pixels after the corrective switch back to the desired desktop.  This results in an ugly "oscillation" of the mouse pointer in the attempt to target locations near the edge of the screen.
Comment 3 Lubos Lunak 2007-06-18 15:28:48 UTC
There is the switch threshold - if you accidentally switch desktops this way, you probably just need to set it higher (or just disable electric borders completely, if your control of the mouse is so poor that you often accidentally activate it).

Comment 4 Hrvoje Niksic 2007-06-18 15:52:37 UTC
That is not quite what I meant.  Hitting *any* small surface with a mouse from a distance requires corrections.  The problem is that, if the surface happens to be located near the edge of the screen, the correction suddenly requires OFFSET*2 more pixels to perform, which is more than the size of the button the user is trying to aim.

The switch threshold makes it harder to navigate between desktops and is a poor fix for this kind of jumpiness on switch.  In fact, I know of no other window manager that warps the mouse away from the border after switching the desktop -- it is counter-productive.

Besides, if you advocate the use of switch threshold, why have the 10-pixel offset by default?
Comment 5 Lubos Lunak 2007-06-21 17:07:19 UTC
SVN commit 678503 by lunakl:

Minimize the offset for electric borders warp.
CCBUG: 129423



 M  +1 -1      workspace.cpp  


--- trunk/KDE/kdebase/workspace/kwin/workspace.cpp #678502:678503
@@ -2246,7 +2246,7 @@
     {
     QPoint pos = _pos;
     int desk = currentDesktop();
-    const int OFFSET = 10;
+    const int OFFSET = 2;
     if( border == ElectricLeft || border == ElectricTopLeft || border == ElectricBottomLeft )
         {
         desk = desktopToLeft( desk );