diff -rc WindowMaker-0.20.0/src/WindowMaker.h WindowMaker-0.20.0-patched/src/WindowMaker.h
*** WindowMaker-0.20.0/src/WindowMaker.h	Sun Sep 20 12:59:40 1998
--- WindowMaker-0.20.0-patched/src/WindowMaker.h	Thu Sep 24 14:39:53 1998
***************
*** 279,284 ****
--- 279,291 ----
      char dont_confirm_kill;	       /* do not confirm Kill application */
  
      char dont_blink;
+ 
+     int edge_resist_time;              /* Time the pointer is at the edge of the 
+                                           screen before switching workspaces */
+ 
+     int corner_threshold;              /* For above: if the mouse is in a box
+ 					  this big in the corner, don't switch
+ 					  workspaces */
      
      /* Appearance options */
      char new_style;		       /* Use newstyle buttons */
diff -rc WindowMaker-0.20.0/src/event.c WindowMaker-0.20.0-patched/src/event.c
*** WindowMaker-0.20.0/src/event.c	Tue Sep 22 09:05:19 1998
--- WindowMaker-0.20.0-patched/src/event.c	Thu Sep 24 14:39:53 1998
***************
*** 1550,1559 ****
  }
  
  
  static void 
  handleMotionNotify(XEvent *event)
  {
!     WMenu *menu;
      WScreen *scr = wScreenForRootWindow(event->xmotion.root);
  
      if (wPreferences.scrollable_menus) {
--- 1550,1691 ----
  }
  
  
+ #define CHANGE_WORKSPACE(which) \
+   { \
+     if((which) != workspace) \
+       { \
+         wschangeto = (which); \
+         wschange = 1; \
+       } \
+   }
+ 
+ 
+ int calcWorkspaceSwitch(WScreen *scr, int *towhich, int *newx, int *newy)
+ {
+   int workspace = scr->current_workspace;
+   int row = workspace/10, column = workspace%10;
+   int lastrow = scr->workspace_count/10;
+   int wschange=0, wschangeto=0;
+ 
+   int w = scr->scr_width, h = scr->scr_height;
+   int junk, x, y;
+   Window junkw;
+   XQueryPointer(dpy, scr->root_win, &junkw, &junkw, &x,
+ 		&y, &junk, &junk, (unsigned *) &junk);
+ 
+   switch(scr->edge_of_screen_state)
+     {
+     case ER_LEFT:
+       if(workspace == 0)
+ 	{
+ 	  if(wPreferences.ws_cycle)
+ 	    CHANGE_WORKSPACE(scr->workspace_count - 1)
+ 	}
+       else CHANGE_WORKSPACE(workspace-1)
+       x = w-3;
+       break;
+ 
+     case ER_RIGHT:
+       if(workspace == scr->workspace_count - 1)
+ 	{
+ 	  if((!wPreferences.ws_advance && wPreferences.ws_cycle) ||
+ 	     scr->workspace_count == MAX_WORKSPACES)
+ 	    CHANGE_WORKSPACE(0)
+ 	  else if(wPreferences.ws_advance)
+ 	    CHANGE_WORKSPACE(scr->workspace_count)
+ 	}
+       else CHANGE_WORKSPACE(workspace+1)
+       x = 2;
+       break;
+ 
+     case ER_TOP:
+       if(row == 0)
+ 	{
+ 	  if(wPreferences.ws_cycle)
+ 	    CHANGE_WORKSPACE(column+(lastrow*10)<scr->workspace_count ?
+              column+(lastrow*10) : column+((lastrow-1)*10))
+ 	}
+       else CHANGE_WORKSPACE(column+((row-1)*10))
+       y = h-3;
+       break;
+      
+     case ER_BOTTOM:
+       if(column+((row+1)*10) >= scr->workspace_count)
+ 	{
+ 	  if(wPreferences.ws_cycle)
+ 	    CHANGE_WORKSPACE(column)
+ 	}
+       else CHANGE_WORKSPACE(column+((row+1)*10))
+       y = 2;
+       break;
+     }
+   
+   *newx = x;
+   *newy = y;
+   *towhich = wschangeto;
+   return wschange;
+ }
+ 
+ 
+ void checkWorkspaceEdgeResistance(WScreen *scr, XEvent *event, 
+ 			 WMCallback *callback, void *callbackdata, int timertime)
+ {
+   int current_edge_of_screen_state;
+   int ct = wPreferences.corner_threshold;
+ 
+   if (ct &&
+       (((event->xmotion.x_root <= ct) &&
+ 	((event->xmotion.y_root <= ct) ||
+ 	(event->xmotion.y_root >= (scr->scr_height - 2 - ct)))) ||
+        ((event->xmotion.x_root >= (scr->scr_width - 2 - ct)) &&
+ 	((event->xmotion.y_root <= ct) ||
+ 	(event->xmotion.y_root >= (scr->scr_height - 2 - ct))))))
+     current_edge_of_screen_state = ER_NOEDGE;
+   else if(event->xmotion.x_root <= 1) 
+     current_edge_of_screen_state = ER_LEFT;
+   else if(event->xmotion.x_root >= (scr->scr_width - 2))
+     current_edge_of_screen_state = ER_RIGHT;
+   else if(event->xmotion.y_root <= 1)
+     current_edge_of_screen_state = ER_TOP;
+   else if(event->xmotion.y_root >= (scr->scr_height - 2))
+     current_edge_of_screen_state = ER_BOTTOM;
+   else current_edge_of_screen_state = ER_NOEDGE;
+   
+   if(current_edge_of_screen_state != scr->edge_of_screen_state) {
+     
+     if(current_edge_of_screen_state == ER_NOEDGE ||
+        scr->edge_of_screen_state != ER_NOEDGE)
+       {
+ 	WMDeleteTimerHandler(scr->edge_resist_timer);
+ 	scr->edge_resist_timer = 0;
+       }
+     
+     if(current_edge_of_screen_state != ER_NOEDGE)
+       scr->edge_resist_timer = 
+ 	WMAddTimerHandler(timertime, callback, callbackdata);
+ 
+     scr->edge_of_screen_state = current_edge_of_screen_state;
+   }
+   
+ }
+ 
+ 
+ static void
+ switchEdgeResist(WScreen *scr)
+ {
+   int wschangeto, x, y;
+   if(calcWorkspaceSwitch(scr, &wschangeto, &x, &y))
+     { 
+       wWorkspaceChange(scr, wschangeto);  
+       XWarpPointer (dpy, None, scr->root_win, 0,0,0,0, x, y);
+     }
+ }
+ 
+ 
  static void 
  handleMotionNotify(XEvent *event)
  {
!     WMenu *menu=NULL;
      WScreen *scr = wScreenForRootWindow(event->xmotion.root);
  
      if (wPreferences.scrollable_menus) {
***************
*** 1571,1574 ****
--- 1703,1711 ----
                  wMenuScroll(menu, event);
          }
      }
+ 
+     if (wPreferences.edge_resist_time && !wPreferences.no_autowrap && menu==NULL) 
+       checkWorkspaceEdgeResistance(scr, event, (WMCallback*)switchEdgeResist, 
+ 			  (void *)scr, wPreferences.edge_resist_time);
  }
+ 
diff -rc WindowMaker-0.20.0/src/funcs.h WindowMaker-0.20.0-patched/src/funcs.h
*** WindowMaker-0.20.0/src/funcs.h	Sat Sep 19 13:48:16 1998
--- WindowMaker-0.20.0-patched/src/funcs.h	Thu Sep 24 14:39:53 1998
***************
*** 41,46 ****
--- 41,50 ----
  
  void DispatchEvent(XEvent *event);
  
+ void checkWorkspaceEdgeResistance(WScreen *scr, XEvent *event, WMCallback *callback, void *callbackdata, int timertime);
+ 
+ int calcWorkspaceSwitch(WScreen *scr, int *towhich, int *newx, int *newy);
+ 
  void WipeDesktop(WScreen *scr);
  
  Bool wRootMenuPerformShortcut(XEvent *event);
diff -rc WindowMaker-0.20.0/src/menu.c WindowMaker-0.20.0-patched/src/menu.c
*** WindowMaker-0.20.0/src/menu.c	Wed Sep  9 05:40:40 1998
--- WindowMaker-0.20.0-patched/src/menu.c	Thu Sep 24 14:39:53 1998
***************
*** 1744,1749 ****
--- 1744,1756 ----
  static void  
  menuExpose(WObjDescriptor *desc, XEvent *event)
  {
+     WScreen *scr = ((WMenu *)(desc->parent))->menu->screen_ptr;
+     if(scr->edge_resist_timer) 
+       {
+ 	WMDeleteTimerHandler(scr->edge_resist_timer);
+ 	scr->edge_resist_timer = 0;
+       }
+ 
      wMenuPaint(desc->parent);
  }
  
diff -rc WindowMaker-0.20.0/src/moveres.c WindowMaker-0.20.0-patched/src/moveres.c
*** WindowMaker-0.20.0/src/moveres.c	Mon Sep 21 10:23:50 1998
--- WindowMaker-0.20.0-patched/src/moveres.c	Thu Sep 24 14:39:53 1998
***************
*** 489,495 ****
      GC gc = wwin->screen_ptr->frame_gc;
      int h = 0;
      int bottom = 0;
!     
      if (!wwin->window_flags.no_titlebar && !wwin->flags.shaded) {
  	h = wwin->screen_ptr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
      }
--- 489,495 ----
      GC gc = wwin->screen_ptr->frame_gc;
      int h = 0;
      int bottom = 0;
! 
      if (!wwin->window_flags.no_titlebar && !wwin->flags.shaded) {
  	h = wwin->screen_ptr->title_font->height + TITLEBAR_EXTRA_HEIGHT;
      }
***************
*** 568,595 ****
  }
  
  
  static void
! crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
!                int new_workspace, int rewind)
  {
!     /* do not let window be unmapped */
!     if (opaque_move) {
! 	wwin->flags.changing_workspace = 1;
! 	wWindowChangeWorkspace(wwin, new_workspace);
!     }
!     /* go to new workspace */
!     wWorkspaceChange(scr, new_workspace);
!     
!     wwin->flags.changing_workspace = 0;
!     
!     if (rewind)
! 	XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
!     else
! 	XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
!     
!     flushMotion();
!     
!     if (!opaque_move) {
  	XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
  		     |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
  		     GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
--- 568,613 ----
  }
  
  
+ typedef struct _CWData
+ {
+   WWindow *wwin;
+   int opaque_move;
+   int warped;
+   int dx, dy;
+ } CWData;
+ 
+ CWData cwData;
+ 
+ 
  static void
! crossWorkspaceEdgeResist(CWData *cwdata, int off_x, int off_y)
  {
!   WWindow *wwin = cwdata->wwin;
!   WScreen *scr = wwin->screen_ptr;
!   int opaque_move = cwdata->opaque_move;
!   
!   int x, y, wschangeto;
! 
!   if(calcWorkspaceSwitch(scr, &wschangeto, &x, &y))
!     {
!       if (opaque_move) 
! 	{
! 	  wwin->flags.changing_workspace = 1;
! 	  wWindowChangeWorkspace(wwin, wschangeto);
! 	}
! 
!       if (!opaque_move)
! 	drawFrames(wwin, wSelectedWindows, cwdata->dx, cwdata->dy, off_x, off_y);
! 
!       wWorkspaceChange(scr, wschangeto);
!       wwin->flags.changing_workspace = 0;
! 
!       XWarpPointer (dpy, None, scr->root_win, 0,0,0,0, x, y);
!       flushMotion();
!       
!       cwdata->warped = 1;
! 
!       if (!opaque_move) 
  	XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
  		     |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
  		     GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
***************
*** 630,642 ****
      int y = wwin->frame_y;
      int ox, oy, orig_x, orig_y;
      int off_x, off_y;
!     short count = 0;		/* for automatic workspace creation */
      int started = 0;
!     int warped = 0;
      /* This needs not to change while moving, else bad things can happen */
      int opaque_move = wPreferences.opaque_move;
      int XOffset, YOffset, origDragX, origDragY;
  
      origDragX = wwin->frame_x;
      origDragY = wwin->frame_y;
      XOffset = origDragX - ev->xbutton.x_root;
--- 648,668 ----
      int y = wwin->frame_y;
      int ox, oy, orig_x, orig_y;
      int off_x, off_y;
! //    short count = 0;		/* for automatic workspace creation */
      int started = 0;
! //    int warped = 0;
      /* This needs not to change while moving, else bad things can happen */
      int opaque_move = wPreferences.opaque_move;
      int XOffset, YOffset, origDragX, origDragY;
  
+     cwData.warped = 0;
+ 
+     if(scr->edge_resist_timer) 
+       {
+ 	WMDeleteTimerHandler(scr->edge_resist_timer);
+ 	scr->edge_resist_timer = 0;
+       }
+ 
      origDragX = wwin->frame_x;
      origDragY = wwin->frame_y;
      XOffset = origDragX - ev->xbutton.x_root;
***************
*** 657,663 ****
      shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
      shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
      while (1) {
! 	if (warped) {
              int junk;
              Window junkw;
      
--- 683,690 ----
      shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
      shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
      while (1) {
! 	if (cwData.warped) {
! //	if (warped) {
              int junk;
              Window junkw;
      
***************
*** 666,671 ****
--- 693,699 ----
  	    XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
  			  &event.xmotion.y_root, &junk, &junk,
  			  (unsigned *) &junk);
+ 	    event.type = MotionNotify;
  	} else {
  	    Window win;
  	    
***************
*** 678,683 ****
--- 706,712 ----
  		while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
  	    }
  	}
+ 	    
  	switch (event.type) {
  	 case KeyPress:
  	    if (wSelectedWindows)
***************
*** 702,711 ****
  	    if (started) {
  		showPosition(wwin, x, y);
  
!                 if (!opaque_move) {
!                     drawFrames(wwin, wSelectedWindows,
!                                ox-orig_x, oy-orig_y, off_x, off_y);
!                 } else {
                      doWindowMove(wwin, event.xmotion.x_root + XOffset,
                                   event.xmotion.y_root + YOffset,
                                   wSelectedWindows,
--- 731,740 ----
  	    if (started) {
  		showPosition(wwin, x, y);
  
! 		if (!opaque_move && !cwData.warped)
! 		    drawFrames(wwin, wSelectedWindows,
! 		               ox-orig_x, oy-orig_y, off_x, off_y);
! 		else if(opaque_move) {
                      doWindowMove(wwin, event.xmotion.x_root + XOffset,
                                   event.xmotion.y_root + YOffset,
                                   wSelectedWindows,
***************
*** 723,790 ****
  		    if (wPreferences.move_display == WDIS_FRAME_CENTER)
  			moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
  		}
! 		if (!warped && !wPreferences.no_autowrap) {
! 		    if (event.xmotion.x_root <= 1) {
! 			if (scr->current_workspace > 0) {
! 			    crossWorkspace(scr, wwin, opaque_move, 
! 					   scr->current_workspace-1, True);
! 			    warped = 1;
! 			    count = 0;
! 			} else if (scr->current_workspace == 0
! 				   && wPreferences.ws_cycle) {
! 			    crossWorkspace(scr, wwin, opaque_move, 
! 					   scr->workspace_count-1, True);
! 			    warped = 1;
! 			    count = 0;			    
! 			}
! 		    } else if (event.xmotion.x_root >= scr->scr_width - 2) {
! 
! 			if (scr->current_workspace == scr->workspace_count-1) {
! 			    if ((!wPreferences.ws_advance && wPreferences.ws_cycle)
! 				|| (scr->workspace_count == MAX_WORKSPACES)) {
! 				crossWorkspace(scr, wwin, opaque_move, 0, False);
! 				warped = 1;
! 				count = 0;
! 			    }
! 			    /* if user insists on trying to go to next
! 			     workspace even when it's already the last,
! 			     create a new one */
! 			    else if ((ox == event.xmotion.x_root)
! 				     && wPreferences.ws_advance) {
! 				
! 				/* detect user "rubbing" the window
! 				 against the edge */
! 				if (count > 0
! 				    && oy - event.xmotion.y_root > MOVE_THRESHOLD)
! 				    count = -(count + 1);
! 				else if (count <= 0
! 					 && event.xmotion.y_root - oy > MOVE_THRESHOLD)
! 				    count = -count + 1;
! 			    }
! 			    /* create a new workspace */
! 			    if (abs(count) > 2) {
! 				/* go to next workspace */
! 				wWorkspaceNew(scr);
! 				
! 				crossWorkspace(scr, wwin, opaque_move, 
! 					       scr->current_workspace+1, False);
! 				warped = 1;
! 				count = 0;
! 			    }
! 			} else if (scr->current_workspace < scr->workspace_count) {
! 			    
! 			    /* go to next workspace */
! 			    crossWorkspace(scr, wwin, opaque_move, 
! 					   scr->current_workspace+1, False);
! 			    warped = 1;
! 			    count = 0;
! 			}
! 		    } else {
! 			count = 0;
! 		    }
! 		} else {
! 		    warped = 0;
! 		}
  	    } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
  		       || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
  		XChangeActivePointerGrab(dpy, ButtonMotionMask
--- 752,767 ----
  		    if (wPreferences.move_display == WDIS_FRAME_CENTER)
  			moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
  		}
! 
! 		if (wPreferences.edge_resist_time && !wPreferences.no_autowrap) 
! 		  {
! 		    cwData.wwin = wwin;
! 		    cwData.opaque_move = opaque_move;
! 		    checkWorkspaceEdgeResistance(scr, &event, (WMCallback*)crossWorkspaceEdgeResist, 
! 					(void *)&cwData, wPreferences.edge_resist_time);
! 		  }
! 		if (cwData.warped) cwData.warped = 0;
! 
  	    } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
  		       || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
  		XChangeActivePointerGrab(dpy, ButtonMotionMask
***************
*** 804,809 ****
--- 781,789 ----
  	    }
  	    ox = event.xmotion.x_root;
  	    oy = event.xmotion.y_root;
+ 
+ 	    cwData.dx = ox - orig_x;
+ 	    cwData.dy = oy - orig_y;
  	    
  	    if (started && !opaque_move)
  		drawFrames(wwin, wSelectedWindows, ox - orig_x, oy - orig_y, off_x, off_y);
***************
*** 862,868 ****
  		WMHandleEvent(&event);
  	    }
  	    break;
! 	}
      }
      return 0;
  }
--- 842,848 ----
  		WMHandleEvent(&event);
  	    }
  	    break;
!         }
      }
      return 0;
  }
diff -rc WindowMaker-0.20.0/src/screen.h WindowMaker-0.20.0-patched/src/screen.h
*** WindowMaker-0.20.0/src/screen.h	Sat Sep 19 13:48:16 1998
--- WindowMaker-0.20.0-patched/src/screen.h	Thu Sep 24 14:39:53 1998
***************
*** 58,63 ****
--- 58,69 ----
  #define WTB_PFOCUSED	4
  #define WTB_MENU	6
  
+ /* EdgeResistance -- tell which edge of the screen the cursor is on */
+ #define ER_NOEDGE       0
+ #define ER_TOP          1
+ #define ER_BOTTOM       2
+ #define ER_LEFT         3
+ #define ER_RIGHT        4
  
  /*
   * each WScreen is saved into a context associated with it's root window
***************
*** 229,234 ****
--- 235,244 ----
      Time last_click_time;
      Window last_click_window;
      int last_click_button;
+ 
+     /* EdgeResistance stuff */
+     WMHandlerID  edge_resist_timer;    
+     int edge_of_screen_state;
      
      /* balloon help data */
      struct _WBalloon *balloon;
diff -rc WindowMaker-0.20.0/src/defaults.c WindowMaker-0.20.0-fp/src/defaults.c
*** WindowMaker-0.20.0/src/defaults.c	Mon Sep 21 15:03:59 1998
--- WindowMaker-0.20.0-fp/src/defaults.c	Thu Sep 24 14:37:57 1998
***************
*** 331,336 ****
--- 331,342 ----
      {"DisableBlinking",	"NO",		NULL,
  	   &wPreferences.dont_blink,	getBool,	NULL
      },
+     {"WorkspaceEdgeResistance",	"1",		NULL,
+ 	   &wPreferences.edge_resist_time,getInt,	NULL
+     },
+     {"CornerThreshold", "0",		NULL,
+ 	   &wPreferences.corner_threshold,getInt,	NULL
+     },
        /* style options */
      {"WidgetColor",	"(solid, gray)",	NULL,
  	  NULL,				getTexture,	setWidgetColor,
