Merge pull request #7259 from jherico/crashes

Crash fixes
This commit is contained in:
Howard Stearns 2016-03-09 16:42:36 -08:00
commit 2b576e86f0
22 changed files with 282 additions and 220 deletions

View file

@ -247,6 +247,7 @@ public:
// Set the heartbeat on launch
DeadlockWatchdogThread() {
setObjectName("Deadlock Watchdog");
QTimer* heartbeatTimer = new QTimer();
// Give the heartbeat an initial value
_heartbeat = usecTimestampNow();
@ -254,6 +255,9 @@ public:
_heartbeat = usecTimestampNow();
});
heartbeatTimer->start(HEARTBEAT_UPDATE_INTERVAL_SECS * MSECS_PER_SECOND);
connect(qApp, &QCoreApplication::aboutToQuit, [this] {
_quit = true;
});
}
void deadlockDetectionCrash() {
@ -262,7 +266,7 @@ public:
}
void run() override {
while (!qApp->isAboutToQuit()) {
while (!_quit) {
QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
auto now = usecTimestampNow();
auto lastHeartbeatAge = now - _heartbeat;
@ -273,6 +277,7 @@ public:
}
static std::atomic<uint64_t> _heartbeat;
bool _quit { false };
};
std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;
@ -1122,8 +1127,6 @@ Application::~Application() {
_octreeProcessor.terminate();
_entityEditSender.terminate();
Menu::getInstance()->deleteLater();
_physicsEngine->setCharacterController(NULL);
ModelEntityItem::cleanupLoadedAnimations();
@ -1168,6 +1171,10 @@ Application::~Application() {
#if 0
ConnexionClient::getInstance().destroy();
#endif
// The window takes ownership of the menu, so this has the side effect of destroying it.
_window->setMenuBar(nullptr);
_window->deleteLater();
qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages
}
@ -1334,7 +1341,7 @@ void Application::initializeUi() {
_keyboardMouseDevice = std::dynamic_pointer_cast<KeyboardMouseDevice>(inputPlugin);
}
}
Menu::setInstance();
_window->setMenuBar(new Menu());
updateInputModes();
auto compositorHelper = DependencyManager::get<CompositorHelper>();

View file

@ -46,15 +46,8 @@
#include "Menu.h"
// Fixme make static member of Menu
static const char* const MENU_PROPERTY_NAME = "com.highfidelity.Menu";
void Menu::setInstance() {
globalInstance<Menu>(MENU_PROPERTY_NAME);
}
Menu* Menu::getInstance() {
return static_cast<Menu*>(ui::Menu::getInstance());
return static_cast<Menu*>(qApp->getWindow()->menuBar());
}
Menu::Menu() {

View file

@ -20,7 +20,6 @@ class Menu : public ui::Menu {
Q_OBJECT
public:
static void setInstance();
static Menu* getInstance();
Menu();
Q_INVOKABLE void addMenuItem(const MenuItemProperties& properties);

View file

@ -23,124 +23,16 @@ PluginContainerProxy::PluginContainerProxy() {
PluginContainerProxy::~PluginContainerProxy() {
}
ui::Menu* PluginContainerProxy::getPrimaryMenu() {
auto appMenu = qApp->_window->menuBar();
auto uiMenu = dynamic_cast<ui::Menu*>(appMenu);
return uiMenu;
}
bool PluginContainerProxy::isForeground() {
return qApp->isForeground() && !qApp->getWindow()->isMinimized();
}
void PluginContainerProxy::addMenu(const QString& menuName) {
Menu::getInstance()->addMenu(menuName);
}
void PluginContainerProxy::removeMenu(const QString& menuName) {
Menu::getInstance()->removeMenu(menuName);
}
QAction* PluginContainerProxy::addMenuItem(PluginType type, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable, bool checked, const QString& groupName) {
auto menu = Menu::getInstance();
MenuWrapper* parentItem = menu->getMenu(path);
QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name);
if (!groupName.isEmpty()) {
QActionGroup* group{ nullptr };
if (!_exclusiveGroups.count(groupName)) {
group = _exclusiveGroups[groupName] = new QActionGroup(menu);
group->setExclusive(true);
} else {
group = _exclusiveGroups[groupName];
}
group->addAction(action);
}
connect(action, &QAction::triggered, [=] {
onClicked(action->isChecked());
});
action->setCheckable(checkable);
action->setChecked(checked);
if (type == PluginType::DISPLAY_PLUGIN) {
_currentDisplayPluginActions.push_back({ path, name });
} else {
_currentInputPluginActions.push_back({ path, name });
}
return action;
}
void PluginContainerProxy::removeMenuItem(const QString& menuName, const QString& menuItem) {
Menu::getInstance()->removeMenuItem(menuName, menuItem);
}
bool PluginContainerProxy::isOptionChecked(const QString& name) {
return Menu::getInstance()->isOptionChecked(name);
}
void PluginContainerProxy::setIsOptionChecked(const QString& path, bool checked) {
Menu::getInstance()->setIsOptionChecked(path, checked);
}
// FIXME there is a bug in the fullscreen setting, where leaving
// fullscreen does not restore the window frame, making it difficult
// or impossible to move or size the window.
// Additionally, setting fullscreen isn't hiding the menu on windows
// make it useless for stereoscopic modes.
void PluginContainerProxy::setFullscreen(const QScreen* target, bool hideMenu) {
auto _window = qApp->getWindow();
if (!_window->isFullScreen()) {
_savedGeometry = _window->geometry();
}
if (nullptr == target) {
// FIXME target the screen where the window currently is
target = qApp->primaryScreen();
}
_window->setGeometry(target->availableGeometry());
_window->windowHandle()->setScreen((QScreen*)target);
_window->showFullScreen();
#ifndef Q_OS_MAC
// also hide the QMainWindow's menuBar
QMenuBar* menuBar = _window->menuBar();
if (menuBar && hideMenu) {
menuBar->setVisible(false);
}
#endif
}
void PluginContainerProxy::unsetFullscreen(const QScreen* avoid) {
auto _window = qApp->getWindow();
_window->showNormal();
QRect targetGeometry = _savedGeometry;
if (avoid != nullptr) {
QRect avoidGeometry = avoid->geometry();
if (avoidGeometry.contains(targetGeometry.topLeft())) {
QScreen* newTarget = qApp->primaryScreen();
if (newTarget == avoid) {
foreach(auto screen, qApp->screens()) {
if (screen != avoid) {
newTarget = screen;
break;
}
}
}
targetGeometry = newTarget->availableGeometry();
}
}
#ifdef Q_OS_MAC
QTimer* timer = new QTimer();
timer->singleShot(2000, [=] {
_window->setGeometry(targetGeometry);
timer->deleteLater();
});
#else
_window->setGeometry(targetGeometry);
#endif
#ifndef Q_OS_MAC
// also show the QMainWindow's menuBar
QMenuBar* menuBar = _window->menuBar();
if (menuBar) {
menuBar->setVisible(true);
}
#endif
}
void PluginContainerProxy::requestReset() {
// We could signal qApp to sequence this, but it turns out that requestReset is only used from within the main thread anyway.
qApp->resetSensors(true);
@ -154,8 +46,8 @@ GLWidget* PluginContainerProxy::getPrimaryWidget() {
return qApp->_glWidget;
}
QWindow* PluginContainerProxy::getPrimaryWindow() {
return qApp->_glWidget->windowHandle();
MainWindow* PluginContainerProxy::getPrimaryWindow() {
return qApp->getWindow();
}
QOpenGLContext* PluginContainerProxy::getPrimaryContext() {
@ -184,13 +76,3 @@ void PluginContainerProxy::releaseOverlayTexture(const gpu::TexturePointer& text
qApp->_applicationOverlay.releaseOverlay(texture);
}
/// settings interface
bool PluginContainerProxy::getBoolSetting(const QString& settingName, bool defaultValue) {
Setting::Handle<bool> settingValue(settingName, defaultValue);
return settingValue.get();
}
void PluginContainerProxy::setBoolSetting(const QString& settingName, bool value) {
Setting::Handle<bool> settingValue(settingName, value);
return settingValue.set(value);
}

View file

@ -14,34 +14,20 @@ class PluginContainerProxy : public QObject, PluginContainer {
Q_OBJECT
PluginContainerProxy();
virtual ~PluginContainerProxy();
virtual void addMenu(const QString& menuName) override;
virtual void removeMenu(const QString& menuName) override;
virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override;
virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override;
virtual bool isOptionChecked(const QString& name) override;
virtual void setIsOptionChecked(const QString& path, bool checked) override;
virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = true) override;
virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override;
virtual void showDisplayPluginsTools() override;
virtual void requestReset() override;
virtual bool makeRenderingContextCurrent() override;
virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override;
virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override;
virtual GLWidget* getPrimaryWidget() override;
virtual QWindow* getPrimaryWindow() override;
virtual MainWindow* getPrimaryWindow() override;
virtual ui::Menu* getPrimaryMenu() override;
virtual QOpenGLContext* getPrimaryContext() override;
virtual bool isForeground() override;
virtual const DisplayPlugin* getActiveDisplayPlugin() const override;
/// settings interface
virtual bool getBoolSetting(const QString& settingName, bool defaultValue) override;
virtual void setBoolSetting(const QString& settingName, bool value) override;
QRect _savedGeometry{ 10, 120, 800, 600 };
std::map<QString, QActionGroup*> _exclusiveGroups;
friend class Application;
};
#endif
#endif

View file

@ -184,6 +184,9 @@ bool OBJReader::isValidTexture(const QByteArray &filename) {
}
QUrl candidateUrl = _url.resolved(QUrl(filename));
QNetworkReply *netReply = request(candidateUrl, true);
if (!netReply) {
return false;
}
bool isValid = netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200);
netReply->deleteLater();
return isValid;
@ -257,6 +260,9 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) {
}
QNetworkReply* OBJReader::request(QUrl& url, bool isTest) {
if (!qApp) {
return nullptr;
}
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest netRequest(url);
QNetworkReply* netReply = isTest ? networkAccessManager.head(netRequest) : networkAccessManager.get(netRequest);

View file

@ -326,6 +326,10 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
void OffscreenQmlSurface::onAboutToQuit() {
QObject::disconnect(&_updateTimer);
// Disconnecting the update timer is insufficient, since the renderer
// may attempting to render already, so we need to explicitly tell the renderer
// to stop
_renderer->aboutToQuit();
}
void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
@ -486,6 +490,9 @@ void OffscreenQmlSurface::updateQuick() {
QMutexLocker lock(&(_renderer->_mutex));
_renderer->post(RENDER);
while (!_renderer->_cond.wait(&(_renderer->_mutex), 100)) {
if (_renderer->_quit) {
return;
}
qApp->processEvents();
}
_render = false;

View file

@ -7,6 +7,14 @@
//
#include "PluginContainer.h"
#include <QtCore/QTimer>
#include <QtGui/QScreen>
#include <QtGui/QWindow>
#include <QtWidgets/QApplication>
#include <ui/Menu.h>
#include <MainWindow.h>
static PluginContainer* INSTANCE{ nullptr };
PluginContainer& PluginContainer::getInstance() {
@ -23,3 +31,131 @@ PluginContainer::~PluginContainer() {
Q_ASSERT(INSTANCE == this);
INSTANCE = nullptr;
};
void PluginContainer::addMenu(const QString& menuName) {
getPrimaryMenu()->addMenu(menuName);
}
void PluginContainer::removeMenu(const QString& menuName) {
getPrimaryMenu()->removeMenu(menuName);
}
QAction* PluginContainer::addMenuItem(PluginType type, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable, bool checked, const QString& groupName) {
auto menu = getPrimaryMenu();
MenuWrapper* parentItem = menu->getMenu(path);
QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name);
if (!groupName.isEmpty()) {
QActionGroup* group { nullptr };
if (!_exclusiveGroups.count(groupName)) {
group = _exclusiveGroups[groupName] = new QActionGroup(menu);
group->setExclusive(true);
} else {
group = _exclusiveGroups[groupName];
}
group->addAction(action);
}
QObject::connect(action, &QAction::triggered, [=] {
onClicked(action->isChecked());
});
action->setCheckable(checkable);
action->setChecked(checked);
if (type == PluginType::DISPLAY_PLUGIN) {
_currentDisplayPluginActions.push_back({ path, name });
} else {
_currentInputPluginActions.push_back({ path, name });
}
return action;
}
void PluginContainer::removeMenuItem(const QString& menuName, const QString& menuItem) {
getPrimaryMenu()->removeMenuItem(menuName, menuItem);
}
bool PluginContainer::isOptionChecked(const QString& name) {
return getPrimaryMenu()->isOptionChecked(name);
}
void PluginContainer::setIsOptionChecked(const QString& path, bool checked) {
getPrimaryMenu()->setIsOptionChecked(path, checked);
}
// FIXME there is a bug in the fullscreen setting, where leaving
// fullscreen does not restore the window frame, making it difficult
// or impossible to move or size the window.
// Additionally, setting fullscreen isn't hiding the menu on windows
// make it useless for stereoscopic modes.
void PluginContainer::setFullscreen(const QScreen* target, bool hideMenu) {
auto _window = getPrimaryWindow();
if (!_window->isFullScreen()) {
_savedGeometry = _window->geometry();
}
if (nullptr == target) {
// FIXME target the screen where the window currently is
target = qApp->primaryScreen();
}
_window->setGeometry(target->availableGeometry());
_window->windowHandle()->setScreen((QScreen*)target);
_window->showFullScreen();
#ifndef Q_OS_MAC
// also hide the QMainWindow's menuBar
QMenuBar* menuBar = _window->menuBar();
if (menuBar && hideMenu) {
menuBar->setVisible(false);
}
#endif
}
void PluginContainer::unsetFullscreen(const QScreen* avoid) {
auto _window = getPrimaryWindow();
_window->showNormal();
QRect targetGeometry = _savedGeometry;
if (avoid != nullptr) {
QRect avoidGeometry = avoid->geometry();
if (avoidGeometry.contains(targetGeometry.topLeft())) {
QScreen* newTarget = qApp->primaryScreen();
if (newTarget == avoid) {
foreach(auto screen, qApp->screens()) {
if (screen != avoid) {
newTarget = screen;
break;
}
}
}
targetGeometry = newTarget->availableGeometry();
}
}
#ifdef Q_OS_MAC
QTimer* timer = new QTimer();
timer->singleShot(2000, [=] {
_window->setGeometry(targetGeometry);
timer->deleteLater();
});
#else
_window->setGeometry(targetGeometry);
#endif
#ifndef Q_OS_MAC
// also show the QMainWindow's menuBar
QMenuBar* menuBar = _window->menuBar();
if (menuBar) {
menuBar->setVisible(true);
}
#endif
}
/// settings interface
bool PluginContainer::getBoolSetting(const QString& settingName, bool defaultValue) {
Setting::Handle<bool> settingValue(settingName, defaultValue);
return settingValue.get();
}
void PluginContainer::setBoolSetting(const QString& settingName, bool value) {
Setting::Handle<bool> settingValue(settingName, value);
return settingValue.set(value);
}

View file

@ -8,10 +8,13 @@
#pragma once
#include <functional>
#include <map>
#include <stdint.h>
#include <QString>
#include <QtCore/QString>
#include <QtCore/QVector>
#include <QtCore/QPair>
#include <QtCore/QRect>
#include "Forward.h"
@ -28,33 +31,44 @@ namespace gpu {
using TexturePointer = std::shared_ptr<Texture>;
}
namespace ui {
class Menu;
}
class QActionGroup;
class MainWindow;
class PluginContainer {
public:
static PluginContainer& getInstance();
PluginContainer();
virtual ~PluginContainer();
virtual void addMenu(const QString& menuName) = 0;
virtual void removeMenu(const QString& menuName) = 0;
virtual QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0;
virtual void removeMenuItem(const QString& menuName, const QString& menuItem) = 0;
virtual bool isOptionChecked(const QString& name) = 0;
virtual void setIsOptionChecked(const QString& path, bool checked) = 0;
virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = false) = 0;
virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0;
void addMenu(const QString& menuName);
void removeMenu(const QString& menuName);
QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "");
void removeMenuItem(const QString& menuName, const QString& menuItem);
bool isOptionChecked(const QString& name);
void setIsOptionChecked(const QString& path, bool checked);
void setFullscreen(const QScreen* targetScreen, bool hideMenu = false);
void unsetFullscreen(const QScreen* avoidScreen = nullptr);
virtual ui::Menu* getPrimaryMenu() = 0;
virtual void showDisplayPluginsTools() = 0;
virtual void requestReset() = 0;
virtual bool makeRenderingContextCurrent() = 0;
virtual void releaseSceneTexture(const gpu::TexturePointer& texture) = 0;
virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) = 0;
virtual GLWidget* getPrimaryWidget() = 0;
virtual QWindow* getPrimaryWindow() = 0;
virtual MainWindow* getPrimaryWindow() = 0;
virtual QOpenGLContext* getPrimaryContext() = 0;
virtual bool isForeground() = 0;
virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0;
/// settings interface
virtual bool getBoolSetting(const QString& settingName, bool defaultValue) = 0;
virtual void setBoolSetting(const QString& settingName, bool value) = 0;
bool getBoolSetting(const QString& settingName, bool defaultValue);
void setBoolSetting(const QString& settingName, bool value);
QVector<QPair<QString, QString>>& currentDisplayActions() {
return _currentDisplayPluginActions;
@ -67,5 +81,6 @@ public:
protected:
QVector<QPair<QString, QString>> _currentDisplayPluginActions;
QVector<QPair<QString, QString>> _currentInputPluginActions;
std::map<QString, QActionGroup*> _exclusiveGroups;
QRect _savedGeometry { 10, 120, 800, 600 };
};

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "SharedUtil.h"
#include <cassert>
#include <cstdlib>
#include <cstdio>
@ -33,7 +35,6 @@
#include "NumericalConstants.h"
#include "OctalCode.h"
#include "SharedLogging.h"
#include "SharedUtil.h"
static int usecTimestampNowAdjust = 0; // in usec
void usecTimestampNowForceClockSkew(int clockSkew) {

View file

@ -24,12 +24,33 @@
#include <QtCore/QDebug>
#include <QtCore/QCoreApplication>
// Access to the global instance pointer to enable setting / unsetting
template <typename T>
std::unique_ptr<T>& globalInstancePointer() {
static std::unique_ptr<T> instancePtr;
return instancePtr;
}
template <typename T>
void setGlobalInstance(const char* propertyName, T* instance) {
globalInstancePointer<T>().reset(instance);
}
template <typename T>
bool destroyGlobalInstance() {
std::unique_ptr<T>& instancePtr = globalInstancePointer<T>();
if (instancePtr.get()) {
instancePtr.reset();
return true;
}
return false;
}
// Provides efficient access to a named global type. By storing the value
// in the QApplication by name we can implement the singleton pattern and
// have the single instance function across DLL boundaries.
template <typename T, typename... Args>
T* globalInstance(const char* propertyName, Args&&... args) {
static std::unique_ptr<T> instancePtr;
static T* resultInstance { nullptr };
static std::mutex mutex;
if (!resultInstance) {
@ -37,10 +58,12 @@ T* globalInstance(const char* propertyName, Args&&... args) {
if (!resultInstance) {
auto variant = qApp->property(propertyName);
if (variant.isNull()) {
// Since we're building the object, store it in a shared_ptr so it's
// destroyed by the destructor of the static instancePtr
instancePtr = std::unique_ptr<T>(new T(std::forward<Args>(args)...));
std::unique_ptr<T>& instancePtr = globalInstancePointer<T>();
if (!instancePtr.get()) {
// Since we're building the object, store it in a shared_ptr so it's
// destroyed by the destructor of the static instancePtr
instancePtr = std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
void* voidInstance = &(*instancePtr);
variant = QVariant::fromValue(voidInstance);
qApp->setProperty(propertyName, variant);
@ -52,6 +75,7 @@ T* globalInstance(const char* propertyName, Args&&... args) {
return resultInstance;
}
const int BYTES_PER_COLOR = 3;
const int BYTES_PER_FLAGS = 1;
typedef unsigned char colorPart;

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "MainWindow.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QEvent>
@ -20,10 +22,8 @@
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QDebug>
#include "MainWindow.h"
#include "Menu.h"
#include "Util.h"
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent),
@ -33,6 +33,10 @@ MainWindow::MainWindow(QWidget* parent) :
setAcceptDrops(true);
}
MainWindow::~MainWindow() {
qDebug() << "Destroying main window";
}
void MainWindow::restoreGeometry() {
// Did not use setGeometry() on purpose,
// see http://doc.qt.io/qt-5/qsettings.html#restoring-the-state-of-a-gui-application

View file

@ -20,6 +20,7 @@ class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = NULL);
~MainWindow();
public slots:
void restoreGeometry();

View file

@ -36,7 +36,16 @@ public:
const QUuid uuid{ QUuid::createUuid() };
static MenuUserData* forObject(QObject* object) {
return static_cast<MenuUserData*>(object->userData(USER_DATA_ID));
if (!object) {
qWarning() << "Attempted to fetch MenuUserData for null object";
return nullptr;
}
auto result = static_cast<MenuUserData*>(object->userData(USER_DATA_ID));
if (!result) {
qWarning() << "Unable to find MenuUserData for object " << object;
return nullptr;
}
return result;
}
private:
@ -105,6 +114,9 @@ void VrMenu::addMenu(QMenu* menu) {
QObject* qmlParent = nullptr;
if (dynamic_cast<QMenu*>(parent)) {
MenuUserData* userData = MenuUserData::forObject(parent);
if (!userData) {
return;
}
qmlParent = findMenuObject(userData->uuid.toString());
} else if (dynamic_cast<QMenuBar*>(parent)) {
qmlParent = _rootMenu;
@ -119,6 +131,10 @@ void VrMenu::addMenu(QMenu* menu) {
Q_UNUSED(invokeResult); // FIXME - apparently we haven't upgraded the Qt on our unix Jenkins environments to 5.5.x
QObject* result = returnedValue.value<QObject*>();
Q_ASSERT(result);
if (!result) {
qWarning() << "Unable to create QML menu for widget menu: " << menu->title();
return;
}
// Bind the QML and Widget together
new MenuUserData(menu, result);
@ -155,6 +171,9 @@ void VrMenu::addAction(QMenu* menu, QAction* action) {
Q_ASSERT(!MenuUserData::forObject(action));
Q_ASSERT(MenuUserData::forObject(menu));
MenuUserData* userData = MenuUserData::forObject(menu);
if (!userData) {
return;
}
QObject* menuQml = findMenuObject(userData->uuid.toString());
Q_ASSERT(menuQml);
QQuickMenuItem* returnedValue { nullptr };
@ -176,6 +195,9 @@ void VrMenu::insertAction(QAction* before, QAction* action) {
{
MenuUserData* beforeUserData = MenuUserData::forObject(before);
Q_ASSERT(beforeUserData);
if (!beforeUserData) {
return;
}
beforeQml = findMenuObject(beforeUserData->uuid.toString());
}
QObject* menu = beforeQml->parent();

View file

@ -18,15 +18,8 @@
#include "Logging.h"
using namespace ui;
static const char* const MENU_PROPERTY_NAME = "com.highfidelity.Menu";
Menu* Menu::getInstance() {
static Menu* instance = globalInstance<Menu>(MENU_PROPERTY_NAME);
return instance;
}
Menu::Menu() {
}
Menu::Menu() {}
void Menu::toggleAdvancedMenus() {
setGroupingIsVisible("Advanced", !getGroupingIsVisible("Advanced"));
@ -223,7 +216,7 @@ void Menu::removeAction(MenuWrapper* menu, const QString& actionName) {
void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) {
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(Menu::getInstance(), "setIsOptionChecked", Qt::BlockingQueuedConnection,
QMetaObject::invokeMethod(this, "setIsOptionChecked", Qt::BlockingQueuedConnection,
Q_ARG(const QString&, menuOption),
Q_ARG(bool, isChecked));
return;
@ -275,7 +268,7 @@ QAction* Menu::getActionFromName(const QString& menuName, MenuWrapper* menu) {
MenuWrapper* Menu::getSubMenuFromName(const QString& menuName, MenuWrapper* menu) {
QAction* action = getActionFromName(menuName, menu);
if (action) {
return MenuWrapper::fromMenu(action->menu());
return _backMap[action->menu()];
}
return NULL;
}
@ -320,7 +313,7 @@ QAction* Menu::getMenuAction(const QString& menuName) {
if (!action) {
break;
}
parent = MenuWrapper::fromMenu(action->menu());
parent = _backMap[action->menu()];
}
return action;
}
@ -357,7 +350,7 @@ MenuWrapper* Menu::addMenu(const QString& menuName, const QString& grouping) {
menu = getSubMenuFromName(menuTreePart.trimmed(), addTo);
if (!menu) {
if (!addTo) {
menu = new MenuWrapper(QMenuBar::addMenu(menuTreePart.trimmed()));
menu = new MenuWrapper(*this, QMenuBar::addMenu(menuTreePart.trimmed()));
} else {
menu = addTo->addMenu(menuTreePart.trimmed());
}
@ -498,11 +491,11 @@ void Menu::removeActionGroup(const QString& groupName) {
removeMenu(groupName);
}
MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) {
MenuWrapper::MenuWrapper(ui::Menu& rootMenu, QMenu* menu) : _rootMenu(rootMenu), _realMenu(menu) {
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->addMenu(menu);
});
_backMap[menu] = this;
_rootMenu._backMap[menu] = this;
}
QList<QAction*> MenuWrapper::actions() {
@ -510,7 +503,7 @@ QList<QAction*> MenuWrapper::actions() {
}
MenuWrapper* MenuWrapper::addMenu(const QString& menuName) {
return new MenuWrapper(_realMenu->addMenu(menuName));
return new MenuWrapper(_rootMenu, _realMenu->addMenu(menuName));
}
void MenuWrapper::setEnabled(bool enabled) {
@ -558,4 +551,3 @@ void MenuWrapper::insertAction(QAction* before, QAction* action) {
});
}
QHash<QMenu*, MenuWrapper*> MenuWrapper::_backMap;

View file

@ -41,14 +41,9 @@ public:
}
private:
MenuWrapper(QMenu* menu);
static MenuWrapper* fromMenu(QMenu* menu) {
return _backMap[menu];
}
MenuWrapper(ui::Menu& rootMenu, QMenu* menu);
ui::Menu& _rootMenu;
QMenu* const _realMenu;
static QHash<QMenu*, MenuWrapper*> _backMap;
friend class ui::Menu;
};
@ -60,7 +55,6 @@ public:
static const int UNSPECIFIED_POSITION = -1;
Menu();
static Menu* getInstance();
void loadSettings();
void saveSettings();
@ -146,8 +140,10 @@ protected:
bool isValidGrouping(const QString& grouping) const { return grouping == "Advanced" || grouping == "Developer"; }
QHash<QString, bool> _groupingVisible;
QHash<QString, QSet<QAction*>> _groupingActions;
QHash<QMenu*, MenuWrapper*> _backMap;
static bool _isSomeSubmenuShown;
friend class ::MenuWrapper;
};
} // namespace ui

View file

@ -8,6 +8,6 @@
set(TARGET_NAME hifiNeuron)
setup_hifi_plugin(Script Qml Widgets)
link_hifi_libraries(shared controllers plugins input-plugins)
link_hifi_libraries(shared controllers ui plugins input-plugins)
target_neuron()

View file

@ -8,5 +8,5 @@
set(TARGET_NAME hifiSdl2)
setup_hifi_plugin(Script Qml Widgets)
link_hifi_libraries(shared controllers plugins input-plugins script-engine)
link_hifi_libraries(shared controllers ui plugins input-plugins script-engine)
target_sdl2()

View file

@ -8,5 +8,5 @@
set(TARGET_NAME hifiSixense)
setup_hifi_plugin(Script Qml Widgets)
link_hifi_libraries(shared controllers plugins input-plugins)
link_hifi_libraries(shared controllers ui plugins input-plugins)
target_sixense()

View file

@ -13,7 +13,7 @@ if (WIN32)
set(TARGET_NAME oculus)
setup_hifi_plugin()
link_hifi_libraries(shared gl gpu controllers plugins display-plugins input-plugins)
link_hifi_libraries(shared gl gpu controllers ui plugins display-plugins input-plugins)
include_hifi_library_headers(octree)

View file

@ -11,7 +11,7 @@ if (WIN32)
add_definitions(-DGLEW_STATIC)
set(TARGET_NAME openvr)
setup_hifi_plugin(OpenGL Script Qml Widgets)
link_hifi_libraries(shared gl networking controllers
link_hifi_libraries(shared gl networking controllers ui
plugins display-plugins input-plugins script-engine
render-utils model gpu render model-networking fbx)

View file

@ -81,26 +81,17 @@ class PluginContainerProxy : public QObject, PluginContainer {
Q_OBJECT
public:
virtual ~PluginContainerProxy() {}
virtual void addMenu(const QString& menuName) override {}
virtual void removeMenu(const QString& menuName) override {}
virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr; }
virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override {}
virtual bool isOptionChecked(const QString& name) override { return false; }
virtual void setIsOptionChecked(const QString& path, bool checked) override {}
virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = true) override {}
virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override {}
virtual void showDisplayPluginsTools() override {}
virtual void requestReset() override {}
virtual bool makeRenderingContextCurrent() override { return true; }
virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override {}
virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override {}
virtual GLWidget* getPrimaryWidget() override { return nullptr; }
virtual QWindow* getPrimaryWindow() override { return nullptr; }
virtual MainWindow* getPrimaryWindow() override { return nullptr; }
virtual QOpenGLContext* getPrimaryContext() override { return nullptr; }
virtual bool isForeground() override { return true; }
virtual ui::Menu* getPrimaryMenu() { return nullptr; }
virtual bool isForeground() override { return true; }
virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr; }
virtual bool getBoolSetting(const QString& settingName, bool defaultValue) override { return defaultValue; }
virtual void setBoolSetting(const QString& settingName, bool value) override { }
};
class MyControllerScriptingInterface : public controller::ScriptingInterface {