diff --git a/FL/Fl_Menu_.H b/FL/Fl_Menu_.H
index d39b751..880a26e 100644
--- a/FL/Fl_Menu_.H
+++ b/FL/Fl_Menu_.H
@@ -164,6 +164,7 @@ public:
   Fl_Color down_color() const {return selection_color();}
   /** For back compatibility, same as selection_color() */
   void down_color(unsigned c) {selection_color(c);}
+  void setonly(Fl_Menu_Item* item);
 };
 
 #endif
diff --git a/src/Fl_Menu_.cxx b/src/Fl_Menu_.cxx
index 53bae04..9d5ffdd 100644
--- a/src/Fl_Menu_.cxx
+++ b/src/Fl_Menu_.cxx
@@ -254,8 +254,9 @@ const Fl_Menu_Item* Fl_Menu_::picked(const Fl_Menu_Item* v) {
   if (v) {
     if (v->radio()) {
       if (!v->value()) { // they are turning on a radio item
-	set_changed();
-	((Fl_Menu_Item*)v)->setonly();
+        set_changed();
+        //((Fl_Menu_Item*)v)->setonly();
+        setonly((Fl_Menu_Item*)v);
       }
       redraw();
     } else if (v->flags & FL_MENU_TOGGLE) {
@@ -276,7 +277,62 @@ const Fl_Menu_Item* Fl_Menu_::picked(const Fl_Menu_Item* v) {
   return v;
 }
 
-/** Turns the radio item "on" for the menu item and turns off adjacent radio items set. */
+/* returns pointer to first Fl_Menu_Item of the submenu containing item,
+ within a menu that starts at start. FL_SUBMENU_POINTER is properly handled.
+ If pnext is non-nil, *pnext is set upon return to item after submenu end.
+ */
+static Fl_Menu_Item *first_submenu_item(Fl_Menu_Item *item, Fl_Menu_Item *start, Fl_Menu_Item **pnext = NULL)
+{
+  Fl_Menu_Item *j = start;
+  while (j->label()) {
+    if (j == item) return start;
+    if (j->submenu()) {
+      Fl_Menu_Item *first;
+      if (j->flags&FL_SUBMENU_POINTER) {
+        first = (Fl_Menu_Item*)j->user_data();
+	first = first_submenu_item(item, first);	// v3
+	if (first) return first;			// v3
+	first = j + 1;					// v3
+      } else {
+        first = j + 1;
+      }
+      first = first_submenu_item(item, first, &j);
+      if (first) return first;
+    }
+    else j++;
+  }
+  if (pnext) *pnext = j+1;
+  return NULL;
+}
+
+/** Turns the radio item "on" for the menu item and turns off adjacent radio items of the same group. */
+void Fl_Menu_::setonly(Fl_Menu_Item* item) {
+  item->flags |= FL_MENU_RADIO | FL_MENU_VALUE;
+  Fl_Menu_Item* j;
+  for (j = item; ; ) {	// go down
+    if (j->flags & FL_MENU_DIVIDER) break; // stop on divider lines
+    j++;
+    if (!j->text || !j->radio()) break; // stop after group
+    j->clear();
+  }
+  Fl_Menu_Item* first; // for the first item of the menu containing item
+  if (item >= menu_ && item < menu_ + size()) {
+    first = menu_;
+  } else { // FL_SUBMENU_POINTER is involved
+    first = first_submenu_item(item, menu_);
+  }
+  if (!first) return;				// STR #3176: v3
+  for (j = item-1; j>=first; j--) { // go up
+    //DEBUG printf("GO UP: WORKING ON: item='%s', flags=%x\n", j->text, j->flags);
+    if (!j->text || (j->flags&FL_MENU_DIVIDER) || !j->radio()) break;
+    j->clear();
+  }
+}
+
+/** Turns the radio item "on" for the menu item and turns off adjacent radio items set.
+ Deprecated: this method is dangerous if radio items are first in the menu.
+ Use Fl_Menu_::setonly(Fl_Menu_Item*) instead.
+ */
 void Fl_Menu_Item::setonly() {
   flags |= FL_MENU_RADIO | FL_MENU_VALUE;
   Fl_Menu_Item* j;
diff --git a/str-3176/test-bug.cxx b/str-3176/test-bug.cxx
new file mode 100644
index 0000000..0b3e9f5
--- /dev/null
+++ b/str-3176/test-bug.cxx
@@ -0,0 +1,32 @@
+#include <FL/Fl.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Menu_Bar.H>
+#include <stdio.h>
+Fl_Menu_Item *G_item = 0;
+void menu_cb(Fl_Widget* w, void* userdata) {
+  Fl_Menu_* mw = (Fl_Menu_*)w;
+  const Fl_Menu_Item* m = mw->mvalue();
+  if (m) printf("%s (userdata=%p)\n", m->label(), m->user_data());
+  // WHEN ITEM "One" IS PICKED, CALL setonly() FOR THE COLOR ITEM
+  if ( strcmp(m->label(), "One") == 0 ) G_item->setonly();	// "old" way
+}
+int main() {
+  static Fl_Menu_Item menutable[] = {
+    {"Red",	0, menu_cb, (void *)0x101, FL_MENU_RADIO},	// group of radio items at /very top/ of menu
+    {"Orange",	0, menu_cb, (void *)0x102, FL_MENU_RADIO},
+    {"Yellow",	0, menu_cb, (void *)0x103, FL_MENU_RADIO},
+    {"Submenu", 0, 0,       0,             FL_SUBMENU},
+      {"One",   0, menu_cb, (void *)0x201, FL_MENU_RADIO},	// picking this calls setonly() on one of the colors
+      {"Two",   0, menu_cb, (void *)0x202, FL_MENU_RADIO},
+      {0},
+    {0}
+  };
+  Fl_Double_Window win(400,200);
+  win.begin();
+    Fl_Menu_Bar menubar(0,0,win.w(),30);
+    menubar.menu(menutable);
+  G_item = (Fl_Menu_Item*)menubar.find_item("Red");	// the color item that will be setonly() when item 'One' is picked
+  win.end();
+  win.show();
+  return Fl::run();
+}
diff --git a/test/menubar.cxx b/test/menubar.cxx
index 07e46f5..de950f4 100644
--- a/test/menubar.cxx
+++ b/test/menubar.cxx
@@ -207,6 +207,7 @@ int main(int argc, char **argv) {
     char buf[100];
     sprintf(buf,"item %d",i);
     hugemenu[i].text = strdup(buf);
+    hugemenu[i].flags = FL_MENU_RADIO;
   }
   Fl_Double_Window window(WIDTH,400);
   window.callback(window_cb);
