diff options
author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2019-07-29 14:16:00 +0200 |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2019-08-08 07:06:05 +0200 |
commit | 1880fba971ed8ae8e813829ff3668132371e88a7 (patch) | |
tree | 9acc8160a35ae17065fd5f3b6d694a24ff02768f /src | |
parent | 36cc171b9314bf77fc84d4273dceb6264aef7134 (diff) |
Android: Fix QMenu on 64 bit
The platform menu tags in Qt are actually the pointers, so they are
64-bit values when the build is 64 bit. Since menu IDs in Android
are 32-bit ints, we cannot cast back and forth like we do. To fix
this, we add a separate hash of menu IDs to allow mapping between
Java and C++. For easier book-keeping, we add the hashes to the
menu bar and menu classes, so that we can easily recycle old menu
IDs when they are no longer in use.
Note that overriding the tag on the menus by calling setTag() will
not work, since Qt Widgets will later override it again by setting
it back to the menu's pointer.
[ChangeLog][Android] Fixed an issue where menus would not work on
64 bit builds.
Task-number: QTBUG-76036
Change-Id: Icaa1d235d4166331669139251656ea0159e85195
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
Diffstat (limited to 'src')
5 files changed, 88 insertions, 12 deletions
diff --git a/src/plugins/platforms/android/androidjnimenu.cpp b/src/plugins/platforms/android/androidjnimenu.cpp index 6f548aba52..e9359def0f 100644 --- a/src/plugins/platforms/android/androidjnimenu.cpp +++ b/src/plugins/platforms/android/androidjnimenu.cpp @@ -225,10 +225,11 @@ namespace QtAndroidMenu QString itemText = removeAmpersandEscapes(item->text()); jstring jtext = env->NewString(reinterpret_cast<const jchar *>(itemText.data()), itemText.length()); + jint menuId = platformMenu->menuId(item); jobject menuItem = env->CallObjectMethod(menu, addMenuItemMethodID, menuNoneValue, - int(item->tag()), + menuId, order++, jtext); env->DeleteLocalRef(jtext); @@ -262,10 +263,11 @@ namespace QtAndroidMenu QString itemText = removeAmpersandEscapes(item->text()); jstring jtext = env->NewString(reinterpret_cast<const jchar *>(itemText.data()), itemText.length()); + jint menuId = visibleMenuBar->menuId(item); jobject menuItem = env->CallObjectMethod(menu, addMenuItemMethodID, menuNoneValue, - int(item->tag()), + menuId, order++, jtext); env->DeleteLocalRef(jtext); @@ -290,7 +292,7 @@ namespace QtAndroidMenu const QAndroidPlatformMenuBar::PlatformMenusType &menus = visibleMenuBar->menus(); if (menus.size() == 1) { // Expanded menu - QAndroidPlatformMenuItem *item = static_cast<QAndroidPlatformMenuItem *>(menus.front()->menuItemForTag(menuId)); + QAndroidPlatformMenuItem *item = static_cast<QAndroidPlatformMenuItem *>(menus.front()->menuItemForId(menuId)); if (item) { if (item->menu()) { showContextMenu(item->menu(), QRect(), env); @@ -301,7 +303,7 @@ namespace QtAndroidMenu } } } else { - QAndroidPlatformMenu *menu = static_cast<QAndroidPlatformMenu *>(visibleMenuBar->menuForTag(menuId)); + QAndroidPlatformMenu *menu = static_cast<QAndroidPlatformMenu *>(visibleMenuBar->menuForId(menuId)); if (menu) showContextMenu(menu, QRect(), env); } @@ -341,7 +343,7 @@ namespace QtAndroidMenu static jboolean onContextItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked) { QMutexLocker lock(&visibleMenuMutex); - QAndroidPlatformMenuItem * item = static_cast<QAndroidPlatformMenuItem *>(visibleMenu->menuItemForTag(menuId)); + QAndroidPlatformMenuItem * item = static_cast<QAndroidPlatformMenuItem *>(visibleMenu->menuItemForId(menuId)); if (item) { if (item->menu()) { showContextMenu(item->menu(), QRect(), env); diff --git a/src/plugins/platforms/android/qandroidplatformmenu.cpp b/src/plugins/platforms/android/qandroidplatformmenu.cpp index d9cecebf2c..7ce603831f 100644 --- a/src/plugins/platforms/android/qandroidplatformmenu.cpp +++ b/src/plugins/platforms/android/qandroidplatformmenu.cpp @@ -62,6 +62,7 @@ void QAndroidPlatformMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatform m_menuItems.end(), static_cast<QAndroidPlatformMenuItem *>(before)), static_cast<QAndroidPlatformMenuItem *>(menuItem)); + m_menuHash.insert(m_nextMenuId++, menuItem); } void QAndroidPlatformMenu::removeMenuItem(QPlatformMenuItem *menuItem) @@ -72,6 +73,21 @@ void QAndroidPlatformMenu::removeMenuItem(QPlatformMenuItem *menuItem) static_cast<QAndroidPlatformMenuItem *>(menuItem)); if (it != m_menuItems.end()) m_menuItems.erase(it); + + { + int maxId = -1; + QHash<int, QPlatformMenuItem *>::iterator it = m_menuHash.begin(); + while (it != m_menuHash.end()) { + if (it.value() == menuItem) { + it = m_menuHash.erase(it); + } else { + maxId = qMax(maxId, it.key()); + ++it; + } + } + + m_nextMenuId = maxId + 1; + } } void QAndroidPlatformMenu::syncMenuItem(QPlatformMenuItem *menuItem) @@ -139,6 +155,16 @@ void QAndroidPlatformMenu::showPopup(const QWindow *parentWindow, const QRect &t QtAndroidMenu::showContextMenu(this, targetRect, QJNIEnvironmentPrivate()); } +QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const +{ + for (QAndroidPlatformMenuItem *menuItem : m_menuItems) { + if (menuItem->tag() == tag) + return menuItem; + } + + return nullptr; +} + QPlatformMenuItem *QAndroidPlatformMenu::menuItemAt(int position) const { if (position < m_menuItems.size()) @@ -146,13 +172,20 @@ QPlatformMenuItem *QAndroidPlatformMenu::menuItemAt(int position) const return 0; } -QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const +int QAndroidPlatformMenu::menuId(QPlatformMenuItem *menu) const { - for (QPlatformMenuItem *menuItem : m_menuItems) { - if (menuItem->tag() == tag) - return menuItem; + QHash<int, QPlatformMenuItem *>::const_iterator it; + for (it = m_menuHash.constBegin(); it != m_menuHash.constEnd(); ++it) { + if (it.value() == menu) + return it.key(); } - return 0; + + return -1; +} + +QPlatformMenuItem *QAndroidPlatformMenu::menuItemForId(int menuId) const +{ + return m_menuHash.value(menuId); } QAndroidPlatformMenu::PlatformMenuItemsType QAndroidPlatformMenu::menuItems() const diff --git a/src/plugins/platforms/android/qandroidplatformmenu.h b/src/plugins/platforms/android/qandroidplatformmenu.h index 47e650f2d7..b1d6a88787 100644 --- a/src/plugins/platforms/android/qandroidplatformmenu.h +++ b/src/plugins/platforms/android/qandroidplatformmenu.h @@ -73,6 +73,8 @@ public: QPlatformMenuItem *menuItemAt(int position) const override; QPlatformMenuItem *menuItemForTag(quintptr tag) const override; + QPlatformMenuItem *menuItemForId(int menuId) const; + int menuId(QPlatformMenuItem *menuItem) const; PlatformMenuItemsType menuItems() const; QMutex *menuItemsMutex(); @@ -84,6 +86,9 @@ private: bool m_enabled; bool m_isVisible; QMutex m_menuItemsMutex; + + int m_nextMenuId = 0; + QHash<int, QPlatformMenuItem *> m_menuHash; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformmenubar.cpp b/src/plugins/platforms/android/qandroidplatformmenubar.cpp index 35930f0628..7c6299b4b7 100644 --- a/src/plugins/platforms/android/qandroidplatformmenubar.cpp +++ b/src/plugins/platforms/android/qandroidplatformmenubar.cpp @@ -61,6 +61,7 @@ void QAndroidPlatformMenuBar::insertMenu(QPlatformMenu *menu, QPlatformMenu *bef m_menus.end(), static_cast<QAndroidPlatformMenu *>(before)), static_cast<QAndroidPlatformMenu *>(menu)); + m_menuHash.insert(m_nextMenuId++, menu); } void QAndroidPlatformMenuBar::removeMenu(QPlatformMenu *menu) @@ -69,6 +70,30 @@ void QAndroidPlatformMenuBar::removeMenu(QPlatformMenu *menu) m_menus.erase(std::find(m_menus.begin(), m_menus.end(), static_cast<QAndroidPlatformMenu *>(menu))); + + int maxId = -1; + QHash<int, QPlatformMenu *>::iterator it = m_menuHash.begin(); + while (it != m_menuHash.end()) { + if (it.value() == menu) { + it = m_menuHash.erase(it); + } else { + maxId = qMax(maxId, it.key()); + ++it; + } + } + + m_nextMenuId = maxId + 1; +} + +int QAndroidPlatformMenuBar::menuId(QPlatformMenu *menu) const +{ + QHash<int, QPlatformMenu *>::const_iterator it; + for (it = m_menuHash.constBegin(); it != m_menuHash.constEnd(); ++it) { + if (it.value() == menu) + return it.key(); + } + + return -1; } void QAndroidPlatformMenuBar::syncMenu(QPlatformMenu *menu) @@ -86,12 +111,17 @@ void QAndroidPlatformMenuBar::handleReparent(QWindow *newParentWindow) QPlatformMenu *QAndroidPlatformMenuBar::menuForTag(quintptr tag) const { - for (QPlatformMenu *menu : m_menus) { + for (QAndroidPlatformMenu *menu : m_menus) { if (menu->tag() == tag) return menu; } - return 0; + return nullptr; +} + +QPlatformMenu *QAndroidPlatformMenuBar::menuForId(int menuId) const +{ + return m_menuHash.value(menuId); } QWindow *QAndroidPlatformMenuBar::parentWindow() const diff --git a/src/plugins/platforms/android/qandroidplatformmenubar.h b/src/plugins/platforms/android/qandroidplatformmenubar.h index f5935b8177..81a26c72f4 100644 --- a/src/plugins/platforms/android/qandroidplatformmenubar.h +++ b/src/plugins/platforms/android/qandroidplatformmenubar.h @@ -43,6 +43,7 @@ #include <qpa/qplatformmenu.h> #include <qvector.h> #include <qmutex.h> +#include <qhash.h> QT_BEGIN_NAMESPACE @@ -60,6 +61,8 @@ public: void syncMenu(QPlatformMenu *menu) override; void handleReparent(QWindow *newParentWindow) override; QPlatformMenu *menuForTag(quintptr tag) const override; + QPlatformMenu *menuForId(int menuId) const; + int menuId(QPlatformMenu *menu) const; QWindow *parentWindow() const override; PlatformMenusType menus() const; @@ -69,6 +72,9 @@ private: PlatformMenusType m_menus; QWindow *m_parentWindow; QMutex m_menusListMutex; + + int m_nextMenuId = 0; + QHash<int, QPlatformMenu *> m_menuHash; }; QT_END_NAMESPACE |