From feb56381d704d61255ca5b0f0ae60e3f4f5f9986 Mon Sep 17 00:00:00 2001
From: markt <markt>
Date: Sun, 21 Jan 2007 18:43:22 +0000
Subject: various changes to menu behavior

---
 ChangeLog           |  6 ++++++
 src/FbTk/Menu.cc    | 32 ++++++++++++++++++++++++--------
 src/FbTk/Menu.hh    |  2 ++
 src/FocusControl.cc | 22 ++++++++++++++--------
 4 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 1d51ace..e5f6d4b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
  (Format: Year/Month/Day)
 Changes for 1.0rc3:
+*07/01/21:
+   * Several fixes for menu behavior (Mark)
+     - always give focus to the menu with the highlighted item
+     - revert focus to menu when no other windows will take it
+     - don't reopen closed submenus when moving the menu
+     FocusControl.cc FbTk/Menu.cc/hh
 *07/01/20:
    * Make sure styles don't change the lastwallpaper in fbsetbg (Mark)
      RootTheme.cc
diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc
index e7fc6d8..5ee329b 100644
--- a/src/FbTk/Menu.cc
+++ b/src/FbTk/Menu.cc
@@ -73,7 +73,7 @@ using std::endl;
 
 namespace FbTk {
 
-static Menu *shown = 0;
+Menu *Menu::shown = 0;
 
 Menu *Menu::s_focused = 0;
 
@@ -365,12 +365,14 @@ void Menu::enterSubmenu() {
 }
 
 void Menu::enterParent() {
-    if (!validIndex(m_which_press) || parent() == 0)
+    if (parent() == 0)
         return;
 
-    Menu *submenu = menuitems[m_which_press]->submenu();
-    if (submenu)
-        submenu->internal_hide();
+    if (validIndex(m_which_press)) {
+        Menu *submenu = menuitems[m_which_press]->submenu();
+        if (submenu)
+            submenu->internal_hide();
+    }
 
     m_active_index = -1;
     //clearItem(m_which_press);
@@ -570,6 +572,13 @@ void Menu::hide() {
 }
 
 void Menu::grabInputFocus() {
+    // if there's a submenu open, focus it instead
+    if (validIndex(m_which_sub) &&
+            menuitems[m_which_sub]->submenu()->isVisible()) {
+        menuitems[m_which_sub]->submenu()->grabInputFocus();
+        return;
+    }
+
     s_focused = this;
 
     // grab input focus
@@ -632,7 +641,8 @@ void Menu::move(int x, int y) {
     if (alpha() < 255)
         clearWindow();
 
-    if (m_which_sub != -1)
+    if (validIndex(m_which_sub) &&
+            menuitems[m_which_sub]->submenu()->isVisible())
         drawSubmenu(m_which_sub);
 }
 
@@ -846,6 +856,10 @@ void Menu::handleEvent(XEvent &event) {
     } else if (event.type == FocusIn) {
         if (s_focused != this)
             s_focused = this;
+        // if there's a submenu open, focus it instead
+        if (validIndex(m_which_sub) &&
+                menuitems[m_which_sub]->submenu()->isVisible())
+            menuitems[m_which_sub]->submenu()->grabInputFocus();
     }
 }
 
@@ -881,7 +895,8 @@ void Menu::buttonReleaseEvent(XButtonEvent &re) {
         if (m_moving) {
             m_moving = false;
 
-            if (m_which_sub != -1)
+            if (validIndex(m_which_sub) &&
+                    menuitems[m_which_sub]->submenu()->isVisible())
                 drawSubmenu(m_which_sub);
 
             if (alpha() < 255) {
@@ -933,7 +948,8 @@ void Menu::motionNotifyEvent(XMotionEvent &me) {
             // clear current highlighted item
             clearItem(m_active_index);
 
-            if (m_which_sub >= 0)
+            if (validIndex(m_which_sub) &&
+                    menuitems[m_which_sub]->submenu()->isVisible())
                 drawSubmenu(m_which_sub);
         } else {
             // we dont call ::move here 'cause we dont want to update transparency
diff --git a/src/FbTk/Menu.hh b/src/FbTk/Menu.hh
index 28eb70a..94a1e6f 100644
--- a/src/FbTk/Menu.hh
+++ b/src/FbTk/Menu.hh
@@ -160,6 +160,7 @@ public:
     bool isItemSelectable(unsigned int index) const;
     inline const MenuTheme &theme() const { return m_theme; }
     inline unsigned char alpha() const { return theme().alpha(); }
+    inline static Menu *shownMenu() { return shown; }
     inline static Menu *focused() { return s_focused; }
     /// @return menuitem at index
     inline const MenuItem *find(unsigned int index) const { return menuitems[index]; }
@@ -235,6 +236,7 @@ private:
     int m_active_index; ///< current highlighted index
 
     Drawable m_root_pm;
+    static Menu *shown; ///< used for determining if there's a menu open at all
     static Menu *s_focused; ///< holds current input focused menu, so one can determine if a menu is focused
     bool m_need_update;
     Timer m_submenu_timer;
diff --git a/src/FocusControl.cc b/src/FocusControl.cc
index 9c82e3e..61d6e87 100644
--- a/src/FocusControl.cc
+++ b/src/FocusControl.cc
@@ -405,14 +405,20 @@ void FocusControl::revertFocus(BScreen &screen) {
     // if setting focus fails, or isn't possible, fallback correctly
     if (!(next_focus && next_focus->focus())) {
         setFocusedWindow(0); // so we don't get dangling m_focused_window pointer
-        switch (screen.focusControl().focusModel()) {
-        case FocusControl::MOUSEFOCUS:
-            XSetInputFocus(screen.rootWindow().display(),
-                           PointerRoot, None, CurrentTime);
-            break;
-        case FocusControl::CLICKFOCUS:
-            screen.rootWindow().setInputFocus(RevertToPointerRoot, CurrentTime);
-            break;
+        // if there's a menu open, focus it
+        if (FbTk::Menu::shownMenu())
+            FbTk::Menu::shownMenu()->grabInputFocus();
+        else {
+            switch (screen.focusControl().focusModel()) {
+            case FocusControl::MOUSEFOCUS:
+                XSetInputFocus(screen.rootWindow().display(),
+                               PointerRoot, None, CurrentTime);
+                break;
+            case FocusControl::CLICKFOCUS:
+                screen.rootWindow().setInputFocus(RevertToPointerRoot,
+                                                  CurrentTime);
+                break;
+            }
         }
     }
 
-- 
cgit v0.11.2