Index: Fl_Tabs.cxx
===================================================================
--- Fl_Tabs.cxx	(revision 10087)
+++ Fl_Tabs.cxx	(working copy)
@@ -154,103 +154,86 @@
   }
 }
 
+// Used Fl_Button::handle() code, and reworked for Fl_Tabs.
+//    o Similar 'drag-off' behavior to allow user to abort the change
+//    o Use push(grp) to make the tab appear 'pushed down', push(0) for release.
+//    o Use oldval to keep track of value() before tab pushed in case we have to revert.
+//    o Handle tooltips (includes a bug fix from previous Fl_Tabs::handle()
+//      for traversing the tab area/group area boundary.
+//
 int Fl_Tabs::handle(int event) {
-
-  Fl_Widget *o;
+  Fl_Widget *o = which(Fl::event_x(), Fl::event_y());	// get tab group for tab user is over
   int i;
-
+  static Fl_Widget *oldval = 0;
   switch (event) {
-
-  case FL_PUSH: {
-    int H = tab_height();
-    if (H >= 0) {
-      if (Fl::event_y() > y()+H) return Fl_Group::handle(event);
-    } else {
-      if (Fl::event_y() < y()+h()+H) return Fl_Group::handle(event);
-    }}
-    /* FALLTHROUGH */
-  case FL_DRAG:
-  case FL_RELEASE: {
-    // PUSH, DRAG, RELEASE..
-    int do_cb=0;
-    if ((o = which(Fl::event_x(), Fl::event_y()))) {	// get tab group for tab user is over
-      if (o != value()) set_changed();		// if over tab, handle change
-      else              clear_changed();
+  case FL_ENTER: /* FALLTHROUGH */
+  case FL_LEAVE:
+    return 1;
+  case FL_PUSH:
+    oldval = 0;
+    push(0);
+    // Push on non-tab part of widget? Let group handle event
+    if ( !o ) return Fl_Group::handle(event);
+    // Pushed on a tab..
+    oldval = value();		// save previous value() (might need to revert)
+    push(o);			// save tab we pressed
+    if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this);
+    //FALLTHROUGH -- let FL_DRAG handle state change
+  case FL_DRAG: {
+    // Dragging during a push that wasn't on a tab? let group handle it
+    if ( !oldval ) {
+      return Fl_Group::handle(event);
     }
-    if (event == FL_RELEASE) {
-      push(0);					// no longer 'pushed'
-      // Over a tab?
-      if (o) {
-	// Handle taking keyboard focus w/visible focus indication
-	if (Fl::visible_focus() && Fl::focus()!=this) { 
-	  Fl::focus(this);
-	  redraw_tabs();
-	}
-	if (value(o)) {				// commit to value, see if it "changed"..
-	  set_changed();				// it changed
-	  do_cb = 
-	    ( (when() & FL_WHEN_RELEASE) &&		// wants cb on RELEASE and..
-	      (when() & FL_WHEN_CHANGED)		// when changed?
-	    ) || (					// ..or..
-	      (when() == FL_WHEN_RELEASE)		// *only* WHEN_RELEASE specified? (default behavior)
-	    ) ? 1 : 0;
-	} else {
-	  clear_changed();				// no change
-	  do_cb = (when() & FL_WHEN_RELEASE &&	// wants cb when RELEASE and..
-		   when() & FL_WHEN_NOT_CHANGED)?1:0;	// ..when no change occurred?
-	}
-      }
-      Fl_Tooltip::current(o);
-    } else {
-      // PUSH or DRAG?
-      //    Be careful; a user can PUSH on a tab, but can abort the change
-      //    if they glide off the tab before a RELEASE. Callbacks on PUSH
-      //    will see a value change, but it may change back on RELEASE if
-      //    the user aborts the change.
-      //
-      push(o);							// DRAG|PUSH -- indicate if still on tab
-      if (o && event == FL_PUSH) {					// still on tab?
-	// See if we should do the callback
-	do_cb = 
-	  ( !(when() & FL_WHEN_RELEASE) &&				// wants callback on PUSH? (ie. NOT RELEASE)
-	    (
-	      ((when() & FL_WHEN_NOT_CHANGED) && !changed()) ||	// want cb if no change and no change occurred?
-	      ((when() & FL_WHEN_CHANGED) && changed())		// want cb if change and change occurred?
-	    )
-	  ) ? 1 : 0;
-      }
+    Fl_Widget *newval = value();		// assume no change to value()
+    if ( (!o||o!=push()) && value()!=oldval ) {	// dragged off pushed tab & value() not yet reverted?
+      newval = oldval;
+    } else if ( push()==o && value()!=o ) {	// over the pushed tab & value() not tab we're over?
+      set_changed();
+      newval = push();
     }
-    if (do_cb)
+    if ( value(newval) &&			// set the value(). Did it change?
+         (when() & FL_WHEN_CHANGED)) {		// want callback when value() changed?
       do_callback();
-    return 1; }
+    }
+    return 1;
+  }
+  case FL_RELEASE:
+    push(0);		// no longer pushed
+    // Release during a push that wasn't on a tab? let group handle it
+    if ( !oldval ) return Fl_Group::handle(event);
+    if (value() == oldval) {
+      // Result was nothing changed?
+      if (when() & FL_WHEN_NOT_CHANGED) do_callback();
+      return 1;
+    }
+    if (when() & FL_WHEN_RELEASE) do_callback();
+    Fl_Tooltip::current(value());
+    return 1;
   case FL_MOVE: {
     int ret = Fl_Group::handle(event);
-    Fl_Widget *o = Fl_Tooltip::current(), *n = o;
     int H = tab_height();
-    if ( (H>=0) && (Fl::event_y()>y()+H) )
-      return ret;
-    else if ( (H<0) && (Fl::event_y() < y()+h()+H) )
-      return ret;
-    else { 
-      n = which(Fl::event_x(), Fl::event_y());
-      if (!n) n = this;
+    Fl_Widget *ntool = o, *ctool = Fl_Tooltip::current();
+    if ( ((H>=0) && (Fl::event_y()>(y()+H))) ||		// inside group area below tabs?
+         ((H<0) && (Fl::event_y()<(y()+h()+H))) ) {	// inside group area above tabs?
+      ntool = 0;					// let group handle it
+    } else {			// inside tab area
+      if (!o) ntool = this;	// not on a tab? (area to right of tabs) use tab widget for tooltip
+      else    ntool = o;	// on a tab, use its tooltip
     }
-    if (n!=o)
-      Fl_Tooltip::enter(n);
-    return ret; }
-  case FL_FOCUS:
-  case FL_UNFOCUS:
-    if (!Fl::visible_focus()) return Fl_Group::handle(event);
-    if (Fl::event() == FL_RELEASE ||
-	Fl::event() == FL_SHORTCUT ||
-	Fl::event() == FL_KEYBOARD ||
-	Fl::event() == FL_FOCUS ||
-	Fl::event() == FL_UNFOCUS) {
-      redraw_tabs();
-      if (Fl::event() == FL_FOCUS) return Fl_Group::handle(event);
-      if (Fl::event() == FL_UNFOCUS) return 0;
-      else return 1;
-    } else return Fl_Group::handle(event);
+    if ( ctool==this && ntool==0 ) {	// *transition* from tab widget to group?
+      ntool = value();			// make sure group's tooltip shown
+    }
+    if ( ntool && Fl_Tooltip::current()!=ntool ) {
+      Fl_Tooltip::enter(ntool);
+    }
+    return ret;
+  }
+  case FL_FOCUS :
+  case FL_UNFOCUS :
+    if (Fl::visible_focus()) {
+      redraw();
+      return 1;
+    } else return 0;
     /* NOTREACHED */
   case FL_KEYBOARD:
     // NOTE:
@@ -345,7 +328,6 @@
     /* FALLTHROUGH */
   default:
     return Fl_Group::handle(event);
-
   }
 }
 
