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 // Set the heartbeat on launch
DeadlockWatchdogThread() { DeadlockWatchdogThread() {
setObjectName("Deadlock Watchdog");
QTimer* heartbeatTimer = new QTimer(); QTimer* heartbeatTimer = new QTimer();
// Give the heartbeat an initial value // Give the heartbeat an initial value
_heartbeat = usecTimestampNow(); _heartbeat = usecTimestampNow();
@ -254,6 +255,9 @@ public:
_heartbeat = usecTimestampNow(); _heartbeat = usecTimestampNow();
}); });
heartbeatTimer->start(HEARTBEAT_UPDATE_INTERVAL_SECS * MSECS_PER_SECOND); heartbeatTimer->start(HEARTBEAT_UPDATE_INTERVAL_SECS * MSECS_PER_SECOND);
connect(qApp, &QCoreApplication::aboutToQuit, [this] {
_quit = true;
});
} }
void deadlockDetectionCrash() { void deadlockDetectionCrash() {
@ -262,7 +266,7 @@ public:
} }
void run() override { void run() override {
while (!qApp->isAboutToQuit()) { while (!_quit) {
QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
auto now = usecTimestampNow(); auto now = usecTimestampNow();
auto lastHeartbeatAge = now - _heartbeat; auto lastHeartbeatAge = now - _heartbeat;
@ -273,6 +277,7 @@ public:
} }
static std::atomic<uint64_t> _heartbeat; static std::atomic<uint64_t> _heartbeat;
bool _quit { false };
}; };
std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat; std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;
@ -1122,8 +1127,6 @@ Application::~Application() {
_octreeProcessor.terminate(); _octreeProcessor.terminate();
_entityEditSender.terminate(); _entityEditSender.terminate();
Menu::getInstance()->deleteLater();
_physicsEngine->setCharacterController(NULL); _physicsEngine->setCharacterController(NULL);
ModelEntityItem::cleanupLoadedAnimations(); ModelEntityItem::cleanupLoadedAnimations();
@ -1168,6 +1171,10 @@ Application::~Application() {
#if 0 #if 0
ConnexionClient::getInstance().destroy(); ConnexionClient::getInstance().destroy();
#endif #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 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); _keyboardMouseDevice = std::dynamic_pointer_cast<KeyboardMouseDevice>(inputPlugin);
} }
} }
Menu::setInstance(); _window->setMenuBar(new Menu());
updateInputModes(); updateInputModes();
auto compositorHelper = DependencyManager::get<CompositorHelper>(); auto compositorHelper = DependencyManager::get<CompositorHelper>();

View file

@ -46,15 +46,8 @@
#include "Menu.h" #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() { Menu* Menu::getInstance() {
return static_cast<Menu*>(ui::Menu::getInstance()); return static_cast<Menu*>(qApp->getWindow()->menuBar());
} }
Menu::Menu() { Menu::Menu() {

View file

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

View file

@ -23,124 +23,16 @@ PluginContainerProxy::PluginContainerProxy() {
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() { bool PluginContainerProxy::isForeground() {
return qApp->isForeground() && !qApp->getWindow()->isMinimized(); 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() { 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. // 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); qApp->resetSensors(true);
@ -154,8 +46,8 @@ GLWidget* PluginContainerProxy::getPrimaryWidget() {
return qApp->_glWidget; return qApp->_glWidget;
} }
QWindow* PluginContainerProxy::getPrimaryWindow() { MainWindow* PluginContainerProxy::getPrimaryWindow() {
return qApp->_glWidget->windowHandle(); return qApp->getWindow();
} }
QOpenGLContext* PluginContainerProxy::getPrimaryContext() { QOpenGLContext* PluginContainerProxy::getPrimaryContext() {
@ -184,13 +76,3 @@ void PluginContainerProxy::releaseOverlayTexture(const gpu::TexturePointer& text
qApp->_applicationOverlay.releaseOverlay(texture); 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 Q_OBJECT
PluginContainerProxy(); PluginContainerProxy();
virtual ~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 showDisplayPluginsTools() override;
virtual void requestReset() override; virtual void requestReset() override;
virtual bool makeRenderingContextCurrent() override; virtual bool makeRenderingContextCurrent() override;
virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override; virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override;
virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override; virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override;
virtual GLWidget* getPrimaryWidget() override; virtual GLWidget* getPrimaryWidget() override;
virtual QWindow* getPrimaryWindow() override; virtual MainWindow* getPrimaryWindow() override;
virtual ui::Menu* getPrimaryMenu() override;
virtual QOpenGLContext* getPrimaryContext() override; virtual QOpenGLContext* getPrimaryContext() override;
virtual bool isForeground() override; virtual bool isForeground() override;
virtual const DisplayPlugin* getActiveDisplayPlugin() const 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; friend class Application;
}; };
#endif #endif

View file

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

View file

@ -326,6 +326,10 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
void OffscreenQmlSurface::onAboutToQuit() { void OffscreenQmlSurface::onAboutToQuit() {
QObject::disconnect(&_updateTimer); 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) { void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
@ -486,6 +490,9 @@ void OffscreenQmlSurface::updateQuick() {
QMutexLocker lock(&(_renderer->_mutex)); QMutexLocker lock(&(_renderer->_mutex));
_renderer->post(RENDER); _renderer->post(RENDER);
while (!_renderer->_cond.wait(&(_renderer->_mutex), 100)) { while (!_renderer->_cond.wait(&(_renderer->_mutex), 100)) {
if (_renderer->_quit) {
return;
}
qApp->processEvents(); qApp->processEvents();
} }
_render = false; _render = false;

View file

@ -7,6 +7,14 @@
// //
#include "PluginContainer.h" #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 }; static PluginContainer* INSTANCE{ nullptr };
PluginContainer& PluginContainer::getInstance() { PluginContainer& PluginContainer::getInstance() {
@ -23,3 +31,131 @@ PluginContainer::~PluginContainer() {
Q_ASSERT(INSTANCE == this); Q_ASSERT(INSTANCE == this);
INSTANCE = nullptr; 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 #pragma once
#include <functional> #include <functional>
#include <map>
#include <stdint.h> #include <stdint.h>
#include <QString>
#include <QtCore/QString>
#include <QtCore/QVector> #include <QtCore/QVector>
#include <QtCore/QPair> #include <QtCore/QPair>
#include <QtCore/QRect>
#include "Forward.h" #include "Forward.h"
@ -28,33 +31,44 @@ namespace gpu {
using TexturePointer = std::shared_ptr<Texture>; using TexturePointer = std::shared_ptr<Texture>;
} }
namespace ui {
class Menu;
}
class QActionGroup;
class MainWindow;
class PluginContainer { class PluginContainer {
public: public:
static PluginContainer& getInstance(); static PluginContainer& getInstance();
PluginContainer(); PluginContainer();
virtual ~PluginContainer(); virtual ~PluginContainer();
virtual void addMenu(const QString& menuName) = 0;
virtual void removeMenu(const QString& menuName) = 0; void addMenu(const QString& menuName);
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; void removeMenu(const QString& menuName);
virtual void removeMenuItem(const QString& menuName, const QString& menuItem) = 0; QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "");
virtual bool isOptionChecked(const QString& name) = 0; void removeMenuItem(const QString& menuName, const QString& menuItem);
virtual void setIsOptionChecked(const QString& path, bool checked) = 0; bool isOptionChecked(const QString& name);
virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = false) = 0; void setIsOptionChecked(const QString& path, bool checked);
virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0;
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 showDisplayPluginsTools() = 0;
virtual void requestReset() = 0; virtual void requestReset() = 0;
virtual bool makeRenderingContextCurrent() = 0; virtual bool makeRenderingContextCurrent() = 0;
virtual void releaseSceneTexture(const gpu::TexturePointer& texture) = 0; virtual void releaseSceneTexture(const gpu::TexturePointer& texture) = 0;
virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) = 0; virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) = 0;
virtual GLWidget* getPrimaryWidget() = 0; virtual GLWidget* getPrimaryWidget() = 0;
virtual QWindow* getPrimaryWindow() = 0; virtual MainWindow* getPrimaryWindow() = 0;
virtual QOpenGLContext* getPrimaryContext() = 0; virtual QOpenGLContext* getPrimaryContext() = 0;
virtual bool isForeground() = 0; virtual bool isForeground() = 0;
virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0; virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0;
/// settings interface /// settings interface
virtual bool getBoolSetting(const QString& settingName, bool defaultValue) = 0; bool getBoolSetting(const QString& settingName, bool defaultValue);
virtual void setBoolSetting(const QString& settingName, bool value) = 0; void setBoolSetting(const QString& settingName, bool value);
QVector<QPair<QString, QString>>& currentDisplayActions() { QVector<QPair<QString, QString>>& currentDisplayActions() {
return _currentDisplayPluginActions; return _currentDisplayPluginActions;
@ -67,5 +81,6 @@ public:
protected: protected:
QVector<QPair<QString, QString>> _currentDisplayPluginActions; QVector<QPair<QString, QString>> _currentDisplayPluginActions;
QVector<QPair<QString, QString>> _currentInputPluginActions; 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 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "SharedUtil.h"
#include <cassert> #include <cassert>
#include <cstdlib> #include <cstdlib>
#include <cstdio> #include <cstdio>
@ -33,7 +35,6 @@
#include "NumericalConstants.h" #include "NumericalConstants.h"
#include "OctalCode.h" #include "OctalCode.h"
#include "SharedLogging.h" #include "SharedLogging.h"
#include "SharedUtil.h"
static int usecTimestampNowAdjust = 0; // in usec static int usecTimestampNowAdjust = 0; // in usec
void usecTimestampNowForceClockSkew(int clockSkew) { void usecTimestampNowForceClockSkew(int clockSkew) {

View file

@ -24,12 +24,33 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QCoreApplication> #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 // Provides efficient access to a named global type. By storing the value
// in the QApplication by name we can implement the singleton pattern and // in the QApplication by name we can implement the singleton pattern and
// have the single instance function across DLL boundaries. // have the single instance function across DLL boundaries.
template <typename T, typename... Args> template <typename T, typename... Args>
T* globalInstance(const char* propertyName, Args&&... args) { T* globalInstance(const char* propertyName, Args&&... args) {
static std::unique_ptr<T> instancePtr;
static T* resultInstance { nullptr }; static T* resultInstance { nullptr };
static std::mutex mutex; static std::mutex mutex;
if (!resultInstance) { if (!resultInstance) {
@ -37,10 +58,12 @@ T* globalInstance(const char* propertyName, Args&&... args) {
if (!resultInstance) { if (!resultInstance) {
auto variant = qApp->property(propertyName); auto variant = qApp->property(propertyName);
if (variant.isNull()) { if (variant.isNull()) {
// Since we're building the object, store it in a shared_ptr so it's std::unique_ptr<T>& instancePtr = globalInstancePointer<T>();
// destroyed by the destructor of the static instancePtr if (!instancePtr.get()) {
instancePtr = std::unique_ptr<T>(new T(std::forward<Args>(args)...)); // 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); void* voidInstance = &(*instancePtr);
variant = QVariant::fromValue(voidInstance); variant = QVariant::fromValue(voidInstance);
qApp->setProperty(propertyName, variant); qApp->setProperty(propertyName, variant);
@ -52,6 +75,7 @@ T* globalInstance(const char* propertyName, Args&&... args) {
return resultInstance; return resultInstance;
} }
const int BYTES_PER_COLOR = 3; const int BYTES_PER_COLOR = 3;
const int BYTES_PER_FLAGS = 1; const int BYTES_PER_FLAGS = 1;
typedef unsigned char colorPart; 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 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "MainWindow.h"
#include <QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QEvent> #include <QEvent>
@ -20,10 +22,8 @@
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QDropEvent> #include <QDropEvent>
#include <QMimeData> #include <QMimeData>
#include <QDebug>
#include "MainWindow.h"
#include "Menu.h"
#include "Util.h"
MainWindow::MainWindow(QWidget* parent) : MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent), QMainWindow(parent),
@ -33,6 +33,10 @@ MainWindow::MainWindow(QWidget* parent) :
setAcceptDrops(true); setAcceptDrops(true);
} }
MainWindow::~MainWindow() {
qDebug() << "Destroying main window";
}
void MainWindow::restoreGeometry() { void MainWindow::restoreGeometry() {
// Did not use setGeometry() on purpose, // Did not use setGeometry() on purpose,
// see http://doc.qt.io/qt-5/qsettings.html#restoring-the-state-of-a-gui-application // 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 Q_OBJECT
public: public:
explicit MainWindow(QWidget* parent = NULL); explicit MainWindow(QWidget* parent = NULL);
~MainWindow();
public slots: public slots:
void restoreGeometry(); void restoreGeometry();

View file

@ -36,7 +36,16 @@ public:
const QUuid uuid{ QUuid::createUuid() }; const QUuid uuid{ QUuid::createUuid() };
static MenuUserData* forObject(QObject* object) { 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: private:
@ -105,6 +114,9 @@ void VrMenu::addMenu(QMenu* menu) {
QObject* qmlParent = nullptr; QObject* qmlParent = nullptr;
if (dynamic_cast<QMenu*>(parent)) { if (dynamic_cast<QMenu*>(parent)) {
MenuUserData* userData = MenuUserData::forObject(parent); MenuUserData* userData = MenuUserData::forObject(parent);
if (!userData) {
return;
}
qmlParent = findMenuObject(userData->uuid.toString()); qmlParent = findMenuObject(userData->uuid.toString());
} else if (dynamic_cast<QMenuBar*>(parent)) { } else if (dynamic_cast<QMenuBar*>(parent)) {
qmlParent = _rootMenu; 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 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*>(); QObject* result = returnedValue.value<QObject*>();
Q_ASSERT(result); Q_ASSERT(result);
if (!result) {
qWarning() << "Unable to create QML menu for widget menu: " << menu->title();
return;
}
// Bind the QML and Widget together // Bind the QML and Widget together
new MenuUserData(menu, result); new MenuUserData(menu, result);
@ -155,6 +171,9 @@ void VrMenu::addAction(QMenu* menu, QAction* action) {
Q_ASSERT(!MenuUserData::forObject(action)); Q_ASSERT(!MenuUserData::forObject(action));
Q_ASSERT(MenuUserData::forObject(menu)); Q_ASSERT(MenuUserData::forObject(menu));
MenuUserData* userData = MenuUserData::forObject(menu); MenuUserData* userData = MenuUserData::forObject(menu);
if (!userData) {
return;
}
QObject* menuQml = findMenuObject(userData->uuid.toString()); QObject* menuQml = findMenuObject(userData->uuid.toString());
Q_ASSERT(menuQml); Q_ASSERT(menuQml);
QQuickMenuItem* returnedValue { nullptr }; QQuickMenuItem* returnedValue { nullptr };
@ -176,6 +195,9 @@ void VrMenu::insertAction(QAction* before, QAction* action) {
{ {
MenuUserData* beforeUserData = MenuUserData::forObject(before); MenuUserData* beforeUserData = MenuUserData::forObject(before);
Q_ASSERT(beforeUserData); Q_ASSERT(beforeUserData);
if (!beforeUserData) {
return;
}
beforeQml = findMenuObject(beforeUserData->uuid.toString()); beforeQml = findMenuObject(beforeUserData->uuid.toString());
} }
QObject* menu = beforeQml->parent(); QObject* menu = beforeQml->parent();

View file

@ -18,15 +18,8 @@
#include "Logging.h" #include "Logging.h"
using namespace ui; using namespace ui;
static const char* const MENU_PROPERTY_NAME = "com.highfidelity.Menu";
Menu* Menu::getInstance() { Menu::Menu() {}
static Menu* instance = globalInstance<Menu>(MENU_PROPERTY_NAME);
return instance;
}
Menu::Menu() {
}
void Menu::toggleAdvancedMenus() { void Menu::toggleAdvancedMenus() {
setGroupingIsVisible("Advanced", !getGroupingIsVisible("Advanced")); setGroupingIsVisible("Advanced", !getGroupingIsVisible("Advanced"));
@ -223,7 +216,7 @@ void Menu::removeAction(MenuWrapper* menu, const QString& actionName) {
void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) {
if (thread() != QThread::currentThread()) { if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(Menu::getInstance(), "setIsOptionChecked", Qt::BlockingQueuedConnection, QMetaObject::invokeMethod(this, "setIsOptionChecked", Qt::BlockingQueuedConnection,
Q_ARG(const QString&, menuOption), Q_ARG(const QString&, menuOption),
Q_ARG(bool, isChecked)); Q_ARG(bool, isChecked));
return; return;
@ -275,7 +268,7 @@ QAction* Menu::getActionFromName(const QString& menuName, MenuWrapper* menu) {
MenuWrapper* Menu::getSubMenuFromName(const QString& menuName, MenuWrapper* menu) { MenuWrapper* Menu::getSubMenuFromName(const QString& menuName, MenuWrapper* menu) {
QAction* action = getActionFromName(menuName, menu); QAction* action = getActionFromName(menuName, menu);
if (action) { if (action) {
return MenuWrapper::fromMenu(action->menu()); return _backMap[action->menu()];
} }
return NULL; return NULL;
} }
@ -320,7 +313,7 @@ QAction* Menu::getMenuAction(const QString& menuName) {
if (!action) { if (!action) {
break; break;
} }
parent = MenuWrapper::fromMenu(action->menu()); parent = _backMap[action->menu()];
} }
return action; return action;
} }
@ -357,7 +350,7 @@ MenuWrapper* Menu::addMenu(const QString& menuName, const QString& grouping) {
menu = getSubMenuFromName(menuTreePart.trimmed(), addTo); menu = getSubMenuFromName(menuTreePart.trimmed(), addTo);
if (!menu) { if (!menu) {
if (!addTo) { if (!addTo) {
menu = new MenuWrapper(QMenuBar::addMenu(menuTreePart.trimmed())); menu = new MenuWrapper(*this, QMenuBar::addMenu(menuTreePart.trimmed()));
} else { } else {
menu = addTo->addMenu(menuTreePart.trimmed()); menu = addTo->addMenu(menuTreePart.trimmed());
} }
@ -498,11 +491,11 @@ void Menu::removeActionGroup(const QString& groupName) {
removeMenu(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::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->addMenu(menu); vrMenu->addMenu(menu);
}); });
_backMap[menu] = this; _rootMenu._backMap[menu] = this;
} }
QList<QAction*> MenuWrapper::actions() { QList<QAction*> MenuWrapper::actions() {
@ -510,7 +503,7 @@ QList<QAction*> MenuWrapper::actions() {
} }
MenuWrapper* MenuWrapper::addMenu(const QString& menuName) { MenuWrapper* MenuWrapper::addMenu(const QString& menuName) {
return new MenuWrapper(_realMenu->addMenu(menuName)); return new MenuWrapper(_rootMenu, _realMenu->addMenu(menuName));
} }
void MenuWrapper::setEnabled(bool enabled) { 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: private:
MenuWrapper(QMenu* menu); MenuWrapper(ui::Menu& rootMenu, QMenu* menu);
ui::Menu& _rootMenu;
static MenuWrapper* fromMenu(QMenu* menu) {
return _backMap[menu];
}
QMenu* const _realMenu; QMenu* const _realMenu;
static QHash<QMenu*, MenuWrapper*> _backMap;
friend class ui::Menu; friend class ui::Menu;
}; };
@ -60,7 +55,6 @@ public:
static const int UNSPECIFIED_POSITION = -1; static const int UNSPECIFIED_POSITION = -1;
Menu(); Menu();
static Menu* getInstance();
void loadSettings(); void loadSettings();
void saveSettings(); void saveSettings();
@ -146,8 +140,10 @@ protected:
bool isValidGrouping(const QString& grouping) const { return grouping == "Advanced" || grouping == "Developer"; } bool isValidGrouping(const QString& grouping) const { return grouping == "Advanced" || grouping == "Developer"; }
QHash<QString, bool> _groupingVisible; QHash<QString, bool> _groupingVisible;
QHash<QString, QSet<QAction*>> _groupingActions; QHash<QString, QSet<QAction*>> _groupingActions;
QHash<QMenu*, MenuWrapper*> _backMap;
static bool _isSomeSubmenuShown; static bool _isSomeSubmenuShown;
friend class ::MenuWrapper;
}; };
} // namespace ui } // namespace ui

View file

@ -8,6 +8,6 @@
set(TARGET_NAME hifiNeuron) set(TARGET_NAME hifiNeuron)
setup_hifi_plugin(Script Qml Widgets) 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() target_neuron()

View file

@ -8,5 +8,5 @@
set(TARGET_NAME hifiSdl2) set(TARGET_NAME hifiSdl2)
setup_hifi_plugin(Script Qml Widgets) 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() target_sdl2()

View file

@ -8,5 +8,5 @@
set(TARGET_NAME hifiSixense) set(TARGET_NAME hifiSixense)
setup_hifi_plugin(Script Qml Widgets) 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() target_sixense()

View file

@ -13,7 +13,7 @@ if (WIN32)
set(TARGET_NAME oculus) set(TARGET_NAME oculus)
setup_hifi_plugin() 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) include_hifi_library_headers(octree)

View file

@ -11,7 +11,7 @@ if (WIN32)
add_definitions(-DGLEW_STATIC) add_definitions(-DGLEW_STATIC)
set(TARGET_NAME openvr) set(TARGET_NAME openvr)
setup_hifi_plugin(OpenGL Script Qml Widgets) 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 plugins display-plugins input-plugins script-engine
render-utils model gpu render model-networking fbx) render-utils model gpu render model-networking fbx)

View file

@ -81,26 +81,17 @@ class PluginContainerProxy : public QObject, PluginContainer {
Q_OBJECT Q_OBJECT
public: public:
virtual ~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 { 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 showDisplayPluginsTools() override {}
virtual void requestReset() override {} virtual void requestReset() override {}
virtual bool makeRenderingContextCurrent() override { return true; } virtual bool makeRenderingContextCurrent() override { return true; }
virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override {} virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override {}
virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override {} virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override {}
virtual GLWidget* getPrimaryWidget() override { return nullptr; } 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 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 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 { class MyControllerScriptingInterface : public controller::ScriptingInterface {