<commit_before>/***********************************************************************************
** MIT License                                                                    **
**                                                                                **
** Copyright (c) 2018 Victor DENIS (victordenis01@gmail.com)                      **
**                                                                                **
** Permission is hereby granted, free of charge, to any person obtaining a copy   **
** of this software and associated documentation files (the "Software"), to deal  **
** in the Software without restriction, including without limitation the rights   **
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      **
** copies of the Software, and to permit persons to whom the Software is          **
** furnished to do so, subject to the following conditions:                       **
**                                                                                **
** The above copyright notice and this permission notice shall be included in all **
** copies or substantial portions of the Software.                                **
**                                                                                **
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     **
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       **
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    **
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER         **
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  **
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  **
** SOFTWARE.                                                                      **
***********************************************************************************/

#include "TitleBar.hpp"

#include <QDesktopWidget>
#include <QScreen>

#include <QSettings>
#include <QtWidgets/QMessageBox>

#include "Application.hpp"

#include "Bookmarks/AddBookmarkDialog.hpp"
#include "Bookmarks/BookmarksToolBar.hpp"

#include "Widgets/Tab/TabWidget.hpp"

namespace Sn {
TitleBar::TitleBar(BookmarksModel* model, BrowserWindow* window, bool showBookmarks) :
		QWidget(window),
		m_window(window),
		m_showBookmarks(showBookmarks)
{
	m_bookmarksToolbar = new BookmarksToolBar(model, m_window);
	m_controlsToolbar = new QToolBar(m_window);

	m_bookmarksToolbar->setFloatable(false);
	m_bookmarksToolbar->installEventFilter(this);
	m_bookmarksToolbar->setContextMenuPolicy(Qt::CustomContextMenu);
	m_controlsToolbar->setFloatable(false);
	m_controlsToolbar->installEventFilter(this);
	m_controlsToolbar->setObjectName(QLatin1String("title-bar"));
	m_controlsToolbar->setContextMenuPolicy(Qt::CustomContextMenu);

	connect(m_bookmarksToolbar, &BookmarksToolBar::orientationChanged, this, &TitleBar::build);
	connect(m_controlsToolbar, &QToolBar::orientationChanged, this, &TitleBar::build);

	restoreToolBarsPositions();

	m_sizePreview = new QFrame(this);
	m_sizePreview->setObjectName(QLatin1String("window-sizepreview"));
	m_sizePreview->setStyleSheet("window-sizepreview{background: rgba(66, 134, 244, 0.5);}");
	m_sizePreview->setAttribute(Qt::WA_TransparentForMouseEvents);
	m_sizePreview->hide();

	build();
}

TitleBar::~TitleBar()
{
	// Empty
}

void TitleBar::setTitle(const QString& title)
{
	if (!m_title)
		return;

	m_title->setText(title);
}

void TitleBar::setShowBookmark(bool show)
{
	m_showBookmarks = show;
	build();
}

void TitleBar::saveToolBarsPositions()
{
	QSettings settings{};

	settings.beginGroup("TitleBar");

	settings.setValue("bookmarks/area", static_cast<int>(m_window->toolBarArea(m_bookmarksToolbar)));
	settings.setValue("bookmarks/locked", m_bookmarksToolbar->isMovable());
	settings.setValue("controls/area", static_cast<int>(m_window->toolBarArea(m_controlsToolbar)));
	settings.setValue("controls/locked", m_controlsToolbar->isMovable());

	settings.endGroup();
}

void TitleBar::restoreToolBarsPositions()
{
	QSettings settings{};

	settings.beginGroup("TitleBar");

	m_window->addToolBar(static_cast<Qt::ToolBarArea>(settings.value("bookmarks/area", Qt::TopToolBarArea).toInt()), m_bookmarksToolbar);
	m_bookmarksToolbar->setMovable(settings.value("bookmarks/locked", true).toBool());
	m_window->addToolBar(static_cast<Qt::ToolBarArea>(settings.value("controls/area", Qt::TopToolBarArea).toInt()), m_controlsToolbar);
	m_controlsToolbar->setMovable(settings.value("controls/locked", true).toBool());

	settings.endGroup();
}

bool TitleBar::isWindowMaximized() const
{
	//return m_window->geometry() == Application::desktop()->availableGeometry(m_window);
	return m_isMaximized;
}

bool TitleBar::eventFilter(QObject* obj, QEvent* event)
{
	if (event->type() == QEvent::MouseButtonPress) {
		mousePressEvent(static_cast<QToolBar*>(obj), static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseMove) {
		mouseMoveEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseButtonRelease) {
		mouseReleaseEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseButtonDblClick) {
		mouseDoubleClickEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::ContextMenu) {
		contextMenuEvent(obj, static_cast<QContextMenuEvent*>(event));
	}
	return QObject::eventFilter(obj, event);
}

void TitleBar::mousePressEvent(QToolBar* toolBar, QMouseEvent* event)
{
	if (event->button() == Qt::LeftButton && ((event->x() >= 10 && toolBar->orientation() == Qt::Horizontal) ||
											  (event->y() >= 10 && toolBar->orientation() == Qt::Vertical))) {
		m_offset = event->globalPos() - m_window->frameGeometry().topLeft();
		m_canMove = true;
		event->accept();
	}
	else
		m_canMove = false;

	QWidget::mousePressEvent(event);
}

void TitleBar::mouseMoveEvent(QMouseEvent* event)
{
	if (event->buttons() & Qt::LeftButton && m_canMove) {
		if (isWindowMaximized() || m_isOnSide) {
			m_window->resize(m_geometry.size());
			m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-maximize"));
			m_toggleMaximize->setIcon(Application::getAppIcon("tb-maximize", "titlebar"));

			m_isMaximized = false;
			m_isOnSide = false;
		}

		m_window->move(event->globalPos() - m_offset);
		event->accept();
	}

	if (QCursor::pos(Application::screenAt(QCursor::pos())).y() <= 0) {
		m_sizePreview->move(0, 0);
		m_sizePreview->resize(1920, 1080);
		m_sizePreview->show();
	}
	else {
		m_sizePreview->hide();
	}

	QWidget::mouseMoveEvent(event);
}

void TitleBar::mouseReleaseEvent(QMouseEvent* event)
{
	QScreen *screen = Application::screenAt(QCursor::pos());
	if (QCursor::pos(screen).y() <= 0) {
		toggleMaximize(true);
	}

	// The move function don't move properly, i need to remove 6 and 8 pixels.
	if (QCursor::pos(screen).x() <= 0) {
		m_geometry = m_window->geometry();
		m_window->resize(screen->size().width() / 2, screen->availableGeometry().height());
		m_window->move((screen->size().width() * Application::screens().indexOf(screen)) - 6, 0);

		m_isOnSide = true;
	}
	// There is 1 px missing on Windows for mouse position
	else if (QCursor::pos(screen).x() >= screen->size().width() - 2) {
		m_geometry = m_window->geometry();
		m_window->resize(screen->size().width() / 2, screen->availableGeometry().height());
		m_window->move((screen->size().width() / 2 * (Application::screens().indexOf(screen) + 1)) - 8, 0);

		m_isOnSide = true;
	}

	m_sizePreview->hide();

	QWidget::mouseReleaseEvent(event);
}

void TitleBar::mouseDoubleClickEvent(QMouseEvent* event)
{
	if (event->buttons() & Qt::LeftButton) {
		toggleMaximize();
	}
}

void TitleBar::contextMenuEvent(QObject* obj, QContextMenuEvent* event)
{
	QMenu menu{};
	QAction* hideShowAction{menu.addAction(tr("Show Bookmarks Bar"))};

	hideShowAction->setCheckable(true);
	hideShowAction->setChecked(m_showBookmarks);
	connect(hideShowAction, &QAction::toggled, this, [=]() {
		setShowBookmark(!m_showBookmarks);
		emit toggleBookmarksBar(m_showBookmarks);
	});

	QAction* addBookmark(menu.addAction(tr("Add Bookmark")));

	connect(addBookmark, &QAction::toggled, this, []() {
		TabWidget* tabWidget = Application::instance()->getWindow()->tabWidget();
		AddBookmarkDialog* dialog{
				new AddBookmarkDialog(tabWidget->weTab()->url().toString(), tabWidget->weTab()->title(), tabWidget,
									  Application::instance()->bookmarksManager())};
	});

	if (obj != nullptr) {
		QToolBar* toolbar = qobject_cast<QToolBar*>(obj);
		QAction* lockToolbar(menu.addAction(tr("Lock Toolbar")));

		lockToolbar->setCheckable(true);
		lockToolbar->setChecked(!toolbar->isMovable());

		connect(lockToolbar, &QAction::toggled, this, [=]() {
			toolbar->setMovable(!toolbar->isMovable());
			Application::instance()->saveSession();
		});
	}

	const QPoint position{ event->globalPos() };
	QPoint point{ position.x(), position.y() + 1 };
	menu.exec(point);
}

void TitleBar::build()
{
#ifdef Q_OS_WIN
	if (m_showBookmarks)
		m_bookmarksToolbar->show();
	else
		m_bookmarksToolbar->hide();

	m_controlsToolbar->clear();

	m_title = new QLabel(m_window->windowTitle(), m_controlsToolbar);
	m_closeButton = new QToolButton(m_controlsToolbar);
	m_toggleMaximize = new QToolButton(m_controlsToolbar);
	m_minimize = new QToolButton(m_controlsToolbar);

	m_title->setObjectName(QLatin1String("titlebar-title"));

	m_closeButton->setObjectName(QLatin1String("titlebar-button-close"));
	m_closeButton->setIcon(Application::getAppIcon("tb-close", "titlebar"));

	m_toggleMaximize->setObjectName(
			QLatin1String(isWindowMaximized() ? "titlebar-button-reverse-maximize" : "titlebar-button-maximize"));
	m_toggleMaximize->setIcon(isWindowMaximized() ? Application::getAppIcon("tb-revert-maximize", "titlebar") :
							  Application::getAppIcon("tb-maximize", "titlebar"));

	m_minimize->setObjectName(QLatin1String("titlebar-button-minimize"));
	m_minimize->setIcon(Application::getAppIcon("tb-minimize", "titlebar"));

	connect(m_closeButton, &QToolButton::clicked, this, &TitleBar::closeWindow);
	connect(m_toggleMaximize, &QToolButton::clicked, this, &TitleBar::toggleMaximize);
	connect(m_minimize, &QToolButton::clicked, this, &TitleBar::minimize);

	QWidget* firstSpacer{new QWidget(m_controlsToolbar)};
	QWidget* secondSpacer{new QWidget(m_controlsToolbar)};

	if (m_controlsToolbar->orientation() == Qt::Horizontal) {
		firstSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
		secondSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
	}
	else if (m_controlsToolbar->orientation() == Qt::Vertical) {
		firstSpacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
		secondSpacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
	}

	m_controlsToolbar->addWidget(firstSpacer);
	m_controlsToolbar->addWidget(m_title);
	m_controlsToolbar->addWidget(secondSpacer);
	m_controlsToolbar->addWidget(m_minimize);
	m_controlsToolbar->addWidget(m_toggleMaximize);
	m_controlsToolbar->addWidget(m_closeButton);
#else
	if (m_showBookmarks)
		m_bookmarksToolbar->show();
	else
		m_bookmarksToolbar->hide();
#endif

	Application::instance()->saveSession();
}

void TitleBar::closeWindow()
{
	m_window->close();
}

void TitleBar::toggleMaximize(bool forceMaximize)
{
	if (isWindowMaximized() && !forceMaximize) {
		if (m_window->isFullScreen())
			m_window->showNormal();

		m_window->setGeometry(m_geometry);
		m_isMaximized = false;

		m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-maximize"));
		m_toggleMaximize->setIcon(Application::getAppIcon("tb-maximize", "titlebar"));
	}
	else {
		if (!m_isOnSide)
			m_geometry = m_window->geometry();

		m_window->setGeometry(Application::desktop()->availableGeometry(m_window));
		m_isMaximized = true;

		m_window->showNormal();

		m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-reverse-maximize"));
		m_toggleMaximize->setIcon(Application::getAppIcon("tb-revert-maximize", "titlebar"));
	}
}

void TitleBar::minimize()
{
	m_window->showMinimized();
}
}
<commit_msg>[Bug] Fix window positionning for multi-screen system<commit_after>/***********************************************************************************
** MIT License                                                                    **
**                                                                                **
** Copyright (c) 2018 Victor DENIS (victordenis01@gmail.com)                      **
**                                                                                **
** Permission is hereby granted, free of charge, to any person obtaining a copy   **
** of this software and associated documentation files (the "Software"), to deal  **
** in the Software without restriction, including without limitation the rights   **
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      **
** copies of the Software, and to permit persons to whom the Software is          **
** furnished to do so, subject to the following conditions:                       **
**                                                                                **
** The above copyright notice and this permission notice shall be included in all **
** copies or substantial portions of the Software.                                **
**                                                                                **
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     **
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       **
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    **
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER         **
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  **
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  **
** SOFTWARE.                                                                      **
***********************************************************************************/

#include "TitleBar.hpp"

#include <QDesktopWidget>
#include <QScreen>

#include <QSettings>
#include <QtWidgets/QMessageBox>

#include "Application.hpp"

#include "Bookmarks/AddBookmarkDialog.hpp"
#include "Bookmarks/BookmarksToolBar.hpp"

#include "Widgets/Tab/TabWidget.hpp"

namespace Sn {
TitleBar::TitleBar(BookmarksModel* model, BrowserWindow* window, bool showBookmarks) :
		QWidget(window),
		m_window(window),
		m_showBookmarks(showBookmarks)
{
	m_bookmarksToolbar = new BookmarksToolBar(model, m_window);
	m_controlsToolbar = new QToolBar(m_window);

	m_bookmarksToolbar->setFloatable(false);
	m_bookmarksToolbar->installEventFilter(this);
	m_bookmarksToolbar->setContextMenuPolicy(Qt::CustomContextMenu);
	m_controlsToolbar->setFloatable(false);
	m_controlsToolbar->installEventFilter(this);
	m_controlsToolbar->setObjectName(QLatin1String("title-bar"));
	m_controlsToolbar->setContextMenuPolicy(Qt::CustomContextMenu);

	connect(m_bookmarksToolbar, &BookmarksToolBar::orientationChanged, this, &TitleBar::build);
	connect(m_controlsToolbar, &QToolBar::orientationChanged, this, &TitleBar::build);

	restoreToolBarsPositions();

	m_sizePreview = new QFrame(this);
	m_sizePreview->setObjectName(QLatin1String("window-sizepreview"));
	m_sizePreview->setStyleSheet("window-sizepreview{background: rgba(66, 134, 244, 0.5);}");
	m_sizePreview->setAttribute(Qt::WA_TransparentForMouseEvents);
	m_sizePreview->hide();

	build();
}

TitleBar::~TitleBar()
{
	// Empty
}

void TitleBar::setTitle(const QString& title)
{
	if (!m_title)
		return;

	m_title->setText(title);
}

void TitleBar::setShowBookmark(bool show)
{
	m_showBookmarks = show;
	build();
}

void TitleBar::saveToolBarsPositions()
{
	QSettings settings{};

	settings.beginGroup("TitleBar");

	settings.setValue("bookmarks/area", static_cast<int>(m_window->toolBarArea(m_bookmarksToolbar)));
	settings.setValue("bookmarks/locked", m_bookmarksToolbar->isMovable());
	settings.setValue("controls/area", static_cast<int>(m_window->toolBarArea(m_controlsToolbar)));
	settings.setValue("controls/locked", m_controlsToolbar->isMovable());

	settings.endGroup();
}

void TitleBar::restoreToolBarsPositions()
{
	QSettings settings{};

	settings.beginGroup("TitleBar");

	m_window->addToolBar(static_cast<Qt::ToolBarArea>(settings.value("bookmarks/area", Qt::TopToolBarArea).toInt()), m_bookmarksToolbar);
	m_bookmarksToolbar->setMovable(settings.value("bookmarks/locked", true).toBool());
	m_window->addToolBar(static_cast<Qt::ToolBarArea>(settings.value("controls/area", Qt::TopToolBarArea).toInt()), m_controlsToolbar);
	m_controlsToolbar->setMovable(settings.value("controls/locked", true).toBool());

	settings.endGroup();
}

bool TitleBar::isWindowMaximized() const
{
	//return m_window->geometry() == Application::desktop()->availableGeometry(m_window);
	return m_isMaximized;
}

bool TitleBar::eventFilter(QObject* obj, QEvent* event)
{
	if (event->type() == QEvent::MouseButtonPress) {
		mousePressEvent(static_cast<QToolBar*>(obj), static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseMove) {
		mouseMoveEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseButtonRelease) {
		mouseReleaseEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseButtonDblClick) {
		mouseDoubleClickEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::ContextMenu) {
		contextMenuEvent(obj, static_cast<QContextMenuEvent*>(event));
	}
	return QObject::eventFilter(obj, event);
}

void TitleBar::mousePressEvent(QToolBar* toolBar, QMouseEvent* event)
{
	if (event->button() == Qt::LeftButton && ((event->x() >= 10 && toolBar->orientation() == Qt::Horizontal) ||
											  (event->y() >= 10 && toolBar->orientation() == Qt::Vertical))) {
		m_offset = event->globalPos() - m_window->frameGeometry().topLeft();
		m_canMove = true;
		event->accept();
	}
	else
		m_canMove = false;

	QWidget::mousePressEvent(event);
}

void TitleBar::mouseMoveEvent(QMouseEvent* event)
{
	if (event->buttons() & Qt::LeftButton && m_canMove) {
		if (isWindowMaximized() || m_isOnSide) {
			m_window->resize(m_geometry.size());
			m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-maximize"));
			m_toggleMaximize->setIcon(Application::getAppIcon("tb-maximize", "titlebar"));

			m_isMaximized = false;
			m_isOnSide = false;
		}

		m_window->move(event->globalPos() - m_offset);
		event->accept();
	}

	if (QCursor::pos(Application::screenAt(QCursor::pos())).y() <= 0) {
		m_sizePreview->move(0, 0);
		m_sizePreview->resize(1920, 1080);
		m_sizePreview->show();
	}
	else {
		m_sizePreview->hide();
	}

	QWidget::mouseMoveEvent(event);
}

void TitleBar::mouseReleaseEvent(QMouseEvent* event)
{
	QScreen *screen = Application::screenAt(QCursor::pos());
	QRect scrrect = screen->geometry();
	setTitle(screen->name() + "; " + QString::number(QCursor::pos(screen).y() - scrrect.y()));
	if (QCursor::pos(screen).y() <= scrrect.y()) {
		toggleMaximize(true);
	}

	// The move function don't move properly, i need to remove 6 and 8 pixels.
	if (QCursor::pos(screen).x() <= scrrect.x()) {
		m_geometry = m_window->geometry();
		m_window->resize(screen->availableGeometry().width() / 2, screen->availableGeometry().height() - 7);
		m_window->move(scrrect.x() - 6, scrrect.y());

		m_isOnSide = true;
	}
	// There is 1 px missing on Windows for mouse position
	else if (QCursor::pos(screen).x() >= scrrect.x() + scrrect.width() - 1) {
		m_geometry = m_window->geometry();
		m_window->resize(screen->availableGeometry().width() / 2, screen->availableGeometry().height() - 7);
		m_window->move(scrrect.x() + (screen->availableGeometry().width() / 2) - 8, scrrect.y());

		m_isOnSide = true;
	}

	m_sizePreview->hide();

	QWidget::mouseReleaseEvent(event);
}

void TitleBar::mouseDoubleClickEvent(QMouseEvent* event)
{
	if (event->buttons() & Qt::LeftButton) {
		toggleMaximize();
	}
}

void TitleBar::contextMenuEvent(QObject* obj, QContextMenuEvent* event)
{
	QMenu menu{};
	QAction* hideShowAction{menu.addAction(tr("Show Bookmarks Bar"))};

	hideShowAction->setCheckable(true);
	hideShowAction->setChecked(m_showBookmarks);
	connect(hideShowAction, &QAction::toggled, this, [=]() {
		setShowBookmark(!m_showBookmarks);
		emit toggleBookmarksBar(m_showBookmarks);
	});

	QAction* addBookmark(menu.addAction(tr("Add Bookmark")));

	connect(addBookmark, &QAction::toggled, this, []() {
		TabWidget* tabWidget = Application::instance()->getWindow()->tabWidget();
		AddBookmarkDialog* dialog{
				new AddBookmarkDialog(tabWidget->weTab()->url().toString(), tabWidget->weTab()->title(), tabWidget,
									  Application::instance()->bookmarksManager())};
	});

	if (obj != nullptr) {
		QToolBar* toolbar = qobject_cast<QToolBar*>(obj);
		QAction* lockToolbar(menu.addAction(tr("Lock Toolbar")));

		lockToolbar->setCheckable(true);
		lockToolbar->setChecked(!toolbar->isMovable());

		connect(lockToolbar, &QAction::toggled, this, [=]() {
			toolbar->setMovable(!toolbar->isMovable());
			Application::instance()->saveSession();
		});
	}

	const QPoint position{ event->globalPos() };
	QPoint point{ position.x(), position.y() + 1 };
	menu.exec(point);
}

void TitleBar::build()
{
#ifdef Q_OS_WIN
	if (m_showBookmarks)
		m_bookmarksToolbar->show();
	else
		m_bookmarksToolbar->hide();

	m_controlsToolbar->clear();

	m_title = new QLabel(m_window->windowTitle(), m_controlsToolbar);
	m_closeButton = new QToolButton(m_controlsToolbar);
	m_toggleMaximize = new QToolButton(m_controlsToolbar);
	m_minimize = new QToolButton(m_controlsToolbar);

	m_title->setObjectName(QLatin1String("titlebar-title"));

	m_closeButton->setObjectName(QLatin1String("titlebar-button-close"));
	m_closeButton->setIcon(Application::getAppIcon("tb-close", "titlebar"));

	m_toggleMaximize->setObjectName(
			QLatin1String(isWindowMaximized() ? "titlebar-button-reverse-maximize" : "titlebar-button-maximize"));
	m_toggleMaximize->setIcon(isWindowMaximized() ? Application::getAppIcon("tb-revert-maximize", "titlebar") :
							  Application::getAppIcon("tb-maximize", "titlebar"));

	m_minimize->setObjectName(QLatin1String("titlebar-button-minimize"));
	m_minimize->setIcon(Application::getAppIcon("tb-minimize", "titlebar"));

	connect(m_closeButton, &QToolButton::clicked, this, &TitleBar::closeWindow);
	connect(m_toggleMaximize, &QToolButton::clicked, this, &TitleBar::toggleMaximize);
	connect(m_minimize, &QToolButton::clicked, this, &TitleBar::minimize);

	QWidget* firstSpacer{new QWidget(m_controlsToolbar)};
	QWidget* secondSpacer{new QWidget(m_controlsToolbar)};

	if (m_controlsToolbar->orientation() == Qt::Horizontal) {
		firstSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
		secondSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
	}
	else if (m_controlsToolbar->orientation() == Qt::Vertical) {
		firstSpacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
		secondSpacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
	}

	m_controlsToolbar->addWidget(firstSpacer);
	m_controlsToolbar->addWidget(m_title);
	m_controlsToolbar->addWidget(secondSpacer);
	m_controlsToolbar->addWidget(m_minimize);
	m_controlsToolbar->addWidget(m_toggleMaximize);
	m_controlsToolbar->addWidget(m_closeButton);
#else
	if (m_showBookmarks)
		m_bookmarksToolbar->show();
	else
		m_bookmarksToolbar->hide();
#endif

	Application::instance()->saveSession();
}

void TitleBar::closeWindow()
{
	m_window->close();
}

void TitleBar::toggleMaximize(bool forceMaximize)
{
	if (isWindowMaximized() && !forceMaximize) {
		if (m_window->isFullScreen())
			m_window->showNormal();

		m_window->setGeometry(m_geometry);
		m_isMaximized = false;

		m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-maximize"));
		m_toggleMaximize->setIcon(Application::getAppIcon("tb-maximize", "titlebar"));
	}
	else {
		if (!m_isOnSide)
			m_geometry = m_window->geometry();

		m_window->setGeometry(Application::desktop()->availableGeometry(m_window));
		m_isMaximized = true;

		m_window->showNormal();

		m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-reverse-maximize"));
		m_toggleMaximize->setIcon(Application::getAppIcon("tb-revert-maximize", "titlebar"));
	}
}

void TitleBar::minimize()
{
	m_window->showMinimized();
}
}
<|endoftext|>


<commit_before>//
//  StoreLogger.cpp
//  ee_x
//
//  Created by Zinge on 5/19/17.
//
//

#include <stack>

#include "ee/store/StoreLogger.hpp"
#include "ee/core/Logger.hpp"
#include "ee/core/LogLevel.hpp"
#include "ee/core/SpinLock.hpp"

namespace ee {
namespace store {
namespace detail {
class DefaultStoreLogger : public StoreLogger {
public:
    virtual void logDebug(const std::string& tag,
                          const std::string& message) override {
        core::Logger::log(core::LogLevel::Debug, tag, message);
    }

    virtual void logError(const std::string& tag,
                          const std::string& message) override {
        core::Logger::log(core::LogLevel::Error, tag, message);
    }
};
} // namespace detail

namespace {
core::SpinLock stackLock;
std::stack<StoreLogger*> stack;
detail::DefaultStoreLogger defaultLogger;

std::stack<StoreLogger*>& getLoggerStack() {
    return stack;
}
} // namespace

StoreLogger& StoreLogger::getInstance() {
    std::lock_guard<core::SpinLock> guard(stackLock);
    return *getLoggerStack().top();
}

StoreLogger::StoreLogger() {
    std::lock_guard<core::SpinLock> guard(stackLock);
    getLoggerStack().push(this);
}

StoreLogger::~StoreLogger() {
    std::lock_guard<core::SpinLock> guard(stackLock);
    getLoggerStack().pop();
}
} // namespace store
} // namespace ee
<commit_msg>- Fix wrong include path.<commit_after>//
//  StoreLogger.cpp
//  ee_x
//
//  Created by Zinge on 5/19/17.
//
//

#include <stack>

#include "ee/store/StoreLogger.hpp"
#include "ee/core/Logger.hpp"
#include "ee/core/LogLevel.hpp"
#include "ee/core/internal/SpinLock.hpp"

namespace ee {
namespace store {
namespace detail {
class DefaultStoreLogger : public StoreLogger {
public:
    virtual void logDebug(const std::string& tag,
                          const std::string& message) override {
        core::Logger::log(core::LogLevel::Debug, tag, message);
    }

    virtual void logError(const std::string& tag,
                          const std::string& message) override {
        core::Logger::log(core::LogLevel::Error, tag, message);
    }
};
} // namespace detail

namespace {
core::SpinLock stackLock;
std::stack<StoreLogger*> stack;
detail::DefaultStoreLogger defaultLogger;

std::stack<StoreLogger*>& getLoggerStack() {
    return stack;
}
} // namespace

StoreLogger& StoreLogger::getInstance() {
    std::lock_guard<core::SpinLock> guard(stackLock);
    return *getLoggerStack().top();
}

StoreLogger::StoreLogger() {
    std::lock_guard<core::SpinLock> guard(stackLock);
    getLoggerStack().push(this);
}

StoreLogger::~StoreLogger() {
    std::lock_guard<core::SpinLock> guard(stackLock);
    getLoggerStack().pop();
}
} // namespace store
} // namespace ee
<|endoftext|>


<commit_before>#include "Window.hpp"

#include "input/InputCallbacks.hpp"
#include "input/Input.hpp"
#include "graphics/GLUtilities.hpp"

#include <imgui/imgui.h>
#include <imgui/imgui_impl_opengl3.h>
#include <imgui/imgui_impl_glfw.h>

#include <GLFW/glfw3.h>

Window::Window(const std::string & name, RenderingConfig & config, bool escapeQuit, bool hidden) :
	_config(config), _allowEscape(escapeQuit) {
	// Initialize glfw, which will create and setup an OpenGL context.
	if(!glfwInit()) {
		Log::Error() << Log::OpenGL << "Could not start GLFW3" << std::endl;
		return;
	}
	const int openGLMajor = 4;
	const int openGLMinor = 0;

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, openGLMajor);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, openGLMinor);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_VISIBLE, hidden ? GLFW_FALSE : GLFW_TRUE);
	glfwWindowHint(GLFW_FOCUSED, hidden ? GLFW_FALSE : GLFW_TRUE);

	if(config.fullscreen) {
		const GLFWvidmode * mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
		glfwWindowHint(GLFW_RED_BITS, mode->redBits);
		glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
		glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
		glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);
		/// \note We might want to impose the configured size here. This means the monitor could be set in a non-native mode.
		_window = glfwCreateWindow(mode->width, mode->height, name.c_str(), glfwGetPrimaryMonitor(), nullptr);
	} else {
		// Create a window with a given size. Width and height are defined in the configuration.
		_window = glfwCreateWindow(int(_config.initialWidth), int(_config.initialHeight), name.c_str(), nullptr, nullptr);
	}

	if(!_window) {
		Log::Error() << Log::OpenGL << "Could not open window with GLFW3" << std::endl;
		glfwTerminate();
		return;
	}

	if(_config.forceAspectRatio) {
		glfwSetWindowAspectRatio(_window, int(_config.initialWidth), int(_config.initialHeight));
	}
	// Bind the OpenGL context and the new window.
	glfwMakeContextCurrent(_window);

	if(gl3wInit()) {
		Log::Error() << Log::OpenGL << "Failed to initialize OpenGL" << std::endl;
		return;
	}
	if(!gl3wIsSupported(openGLMajor, openGLMinor)) {
		Log::Error() << Log::OpenGL << "OpenGL " << openGLMajor << "." << openGLMinor << " not supported\n"
					 << std::endl;
		return;
	}

	// Setup the GPU state.
	GLUtilities::setup();

	// Setup callbacks for various interactions and inputs.
	glfwSetFramebufferSizeCallback(_window, resize_callback);		  // Resizing the window
	glfwSetKeyCallback(_window, key_callback);						  // Pressing a key
	glfwSetCharCallback(_window, char_callback);						  // Outputing a text char (for ImGui)
	glfwSetMouseButtonCallback(_window, mouse_button_callback);		  // Clicking the mouse buttons
	glfwSetCursorPosCallback(_window, cursor_pos_callback);			  // Moving the cursor
	glfwSetScrollCallback(_window, scroll_callback);					  // Scrolling
	glfwSetJoystickCallback(joystick_callback);						  // Joystick
	glfwSetWindowIconifyCallback(_window, iconify_callback);			  // Window minimization
	glfwSwapInterval(_config.vsync ? (_config.rate == 30 ? 2 : 1) : 0); // 60 FPS V-sync

	setupImGui();

	// Check the window position and size (if we are on a screen smaller than the initial size).
	glfwGetWindowPos(_window, &_config.windowFrame[0], &_config.windowFrame[1]);
	glfwGetWindowSize(_window, &_config.windowFrame[2], &_config.windowFrame[3]);

	// On HiDPI screens, we have to consider the internal resolution for all framebuffers size.
	int width, height;
	glfwGetFramebufferSize(_window, &width, &height);
	config.screenResolution = glm::vec2(width, height);

	// Compute point density by computing the ratio.
	const float screenDensity = float(width) / float(_config.windowFrame[2]);
	Input::manager().densityEvent(screenDensity);

	// Update the resolution.
	Input::manager().resizeEvent(width, height);
}

void Window::perform(Action action) {
	switch(action) {
		case Action::Quit:
			glfwSetWindowShouldClose(_window, GLFW_TRUE);
			break;
		case Action::Vsync: {
			if(_config.vsync) {
				glfwSwapInterval(0);
			} else {
				glfwSwapInterval(_config.rate == 30 ? 2 : 1);
			}
			_config.vsync = !_config.vsync;
			break;
		}
		case Action::Fullscreen: {
			// Are we currently fullscreen?
			const bool fullscreen = glfwGetWindowMonitor(_window) != nullptr;

			if(fullscreen) {
				// Restore the window position and size.
				glfwSetWindowMonitor(_window, nullptr, _config.windowFrame[0], _config.windowFrame[1], _config.windowFrame[2], _config.windowFrame[3], 0);
				// Check the window position and size (if we are on a screen smaller than the initial size).
				glfwGetWindowPos(_window, &_config.windowFrame[0], &_config.windowFrame[1]);
				glfwGetWindowSize(_window, &_config.windowFrame[2], &_config.windowFrame[3]);
			} else {
				// Backup the window current frame.
				glfwGetWindowPos(_window, &_config.windowFrame[0], &_config.windowFrame[1]);
				glfwGetWindowSize(_window, &_config.windowFrame[2], &_config.windowFrame[3]);
				// Move to fullscreen on the primary monitor.
				GLFWmonitor * monitor	= glfwGetPrimaryMonitor();
				const GLFWvidmode * mode = glfwGetVideoMode(monitor);
				glfwSetWindowMonitor(_window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
			}
			_config.fullscreen = !fullscreen;
			// On some hardware, V-sync options can be lost.
			glfwSwapInterval(_config.vsync ? (_config.rate == 30 ? 2 : 1) : 0);

			// On HiDPI screens, we have to consider the internal resolution for all framebuffers size.
			int width, height;
			glfwGetFramebufferSize(_window, &width, &height);
			_config.screenResolution = glm::vec2(width, height);

			int wwidth, hheight;
			glfwGetWindowSize(_window, &wwidth, &hheight);
			// Compute point density by computing the ratio.
			const float screenDensity = float(width) / float(wwidth);
			Input::manager().densityEvent(screenDensity);

			// Update the resolution.
			Input::manager().resizeEvent(width, height);
		} break;
		default:
			break;
	}
}

bool Window::nextFrame() {
	if(_frameStarted){
		// Render the interface.
		ImGui::Render();
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
		//Display the result for the current rendering loop.
		glfwSwapBuffers(_window);
	}
	// Update events (inputs,...).
	Input::manager().update();
	// Handle quitting.
	if(_allowEscape && Input::manager().pressed(Input::Key::Escape)) {
		perform(Action::Quit);
	}
	// Start new GUI frame.
	ImGui_ImplOpenGL3_NewFrame();
	ImGui_ImplGlfw_NewFrame();
	ImGui::NewFrame();
	_frameStarted = true;
	return !glfwWindowShouldClose(_window);
}

Window::~Window() {
	// Make sure rendering is done.
	if(_frameStarted){
		ImGui::EndFrame();
	}
	GLUtilities::sync();
	// Clean the interface.
	ImGui_ImplOpenGL3_Shutdown();
	ImGui_ImplGlfw_Shutdown();
	ImGui::DestroyContext();
	// Close GL context and any other GLFW resources.
	glfwDestroyWindow(_window);
	glfwTerminate();
}

void Window::setupImGui() {
	ImGui::CreateContext();
	ImGuiIO & io = ImGui::GetIO();
	(void)io;
	ImGui_ImplGlfw_InitForOpenGL(_window, false);
	ImGui_ImplOpenGL3_Init("#version 400");

	// Customize the style.
	ImGui::StyleColorsDark();
	ImGuiStyle & style = ImGui::GetStyle();
	// Colors.
	ImVec4 * colors						  = style.Colors;
	colors[ImGuiCol_WindowBg]			  = ImVec4(0.04f, 0.04f, 0.04f, 0.94f);
	colors[ImGuiCol_FrameBg]			  = ImVec4(0.16f, 0.16f, 0.16f, 0.54f);
	colors[ImGuiCol_FrameBgHovered]		  = ImVec4(0.36f, 0.36f, 0.36f, 0.40f);
	colors[ImGuiCol_FrameBgActive]		  = ImVec4(0.54f, 0.54f, 0.54f, 0.67f);
	colors[ImGuiCol_TitleBgActive]		  = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
	colors[ImGuiCol_ScrollbarGrab]		  = ImVec4(0.17f, 0.17f, 0.17f, 1.00f);
	colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.34f, 0.34f, 0.34f, 1.00f);
	colors[ImGuiCol_ScrollbarGrabActive]  = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
	colors[ImGuiCol_CheckMark]			  = ImVec4(0.84f, 0.84f, 0.84f, 1.00f);
	colors[ImGuiCol_SliderGrab]			  = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
	colors[ImGuiCol_SliderGrabActive]	 = ImVec4(0.64f, 0.64f, 0.64f, 1.00f);
	colors[ImGuiCol_Button]				  = ImVec4(0.68f, 0.68f, 0.68f, 0.40f);
	colors[ImGuiCol_ButtonHovered]		  = ImVec4(0.40f, 0.40f, 0.40f, 1.00f);
	colors[ImGuiCol_ButtonActive]		  = ImVec4(0.53f, 0.53f, 0.53f, 1.00f);
	colors[ImGuiCol_Header]				  = ImVec4(0.57f, 0.57f, 0.57f, 0.31f);
	colors[ImGuiCol_HeaderHovered]		  = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
	colors[ImGuiCol_HeaderActive]		  = ImVec4(0.52f, 0.52f, 0.52f, 1.00f);
	colors[ImGuiCol_Separator]			  = ImVec4(0.41f, 0.41f, 0.41f, 0.50f);
	colors[ImGuiCol_SeparatorHovered]	 = ImVec4(0.43f, 0.43f, 0.43f, 0.78f);
	colors[ImGuiCol_SeparatorActive]	  = ImVec4(0.44f, 0.44f, 0.44f, 1.00f);
	colors[ImGuiCol_ResizeGrip]			  = ImVec4(1.00f, 1.00f, 1.00f, 0.25f);
	colors[ImGuiCol_ResizeGripHovered]	= ImVec4(0.84f, 0.84f, 0.84f, 0.67f);
	colors[ImGuiCol_ResizeGripActive]	 = ImVec4(0.88f, 0.88f, 0.88f, 0.95f);
	colors[ImGuiCol_PlotLinesHovered]	 = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
	colors[ImGuiCol_PlotHistogram]		  = ImVec4(0.62f, 0.62f, 0.62f, 1.00f);
	colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
	colors[ImGuiCol_TextSelectedBg]		  = ImVec4(0.67f, 0.67f, 0.67f, 0.35f);
	colors[ImGuiCol_DragDropTarget]		  = ImVec4(0.83f, 0.83f, 0.83f, 0.90f);
	colors[ImGuiCol_NavHighlight]		  = ImVec4(0.88f, 0.88f, 0.88f, 1.00f);
	// Frames.
	style.FrameRounding		 = 5.0f;
	style.GrabRounding		 = 3.0f;
	style.WindowRounding	 = 5.0f;
	style.ScrollbarRounding  = 12.0f;
	style.ScrollbarSize		 = 12.0f;
	style.WindowTitleAlign.x = 0.5f;
	style.FramePadding.y	 = 4.0f;
	style.ItemSpacing.y		 = 3.0f;
}
<commit_msg>Window: notify when backbuffer resized.<commit_after>#include "Window.hpp"

#include "input/InputCallbacks.hpp"
#include "input/Input.hpp"
#include "graphics/GLUtilities.hpp"
#include "graphics/Framebuffer.hpp"

#include <imgui/imgui.h>
#include <imgui/imgui_impl_opengl3.h>
#include <imgui/imgui_impl_glfw.h>

#include <GLFW/glfw3.h>

Window::Window(const std::string & name, RenderingConfig & config, bool escapeQuit, bool hidden) :
	_config(config), _allowEscape(escapeQuit) {
	// Initialize glfw, which will create and setup an OpenGL context.
	if(!glfwInit()) {
		Log::Error() << Log::OpenGL << "Could not start GLFW3" << std::endl;
		return;
	}
	const int openGLMajor = 4;
	const int openGLMinor = 0;

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, openGLMajor);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, openGLMinor);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_VISIBLE, hidden ? GLFW_FALSE : GLFW_TRUE);
	glfwWindowHint(GLFW_FOCUSED, hidden ? GLFW_FALSE : GLFW_TRUE);

	if(config.fullscreen) {
		const GLFWvidmode * mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
		glfwWindowHint(GLFW_RED_BITS, mode->redBits);
		glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
		glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
		glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);
		/// \note We might want to impose the configured size here. This means the monitor could be set in a non-native mode.
		_window = glfwCreateWindow(mode->width, mode->height, name.c_str(), glfwGetPrimaryMonitor(), nullptr);
	} else {
		// Create a window with a given size. Width and height are defined in the configuration.
		_window = glfwCreateWindow(int(_config.initialWidth), int(_config.initialHeight), name.c_str(), nullptr, nullptr);
	}

	if(!_window) {
		Log::Error() << Log::OpenGL << "Could not open window with GLFW3" << std::endl;
		glfwTerminate();
		return;
	}

	if(_config.forceAspectRatio) {
		glfwSetWindowAspectRatio(_window, int(_config.initialWidth), int(_config.initialHeight));
	}
	// Bind the OpenGL context and the new window.
	glfwMakeContextCurrent(_window);

	if(gl3wInit()) {
		Log::Error() << Log::OpenGL << "Failed to initialize OpenGL" << std::endl;
		return;
	}
	if(!gl3wIsSupported(openGLMajor, openGLMinor)) {
		Log::Error() << Log::OpenGL << "OpenGL " << openGLMajor << "." << openGLMinor << " not supported\n"
					 << std::endl;
		return;
	}

	// Setup the GPU state.
	GLUtilities::setup();

	// Setup callbacks for various interactions and inputs.
	glfwSetFramebufferSizeCallback(_window, resize_callback);		  // Resizing the window
	glfwSetKeyCallback(_window, key_callback);						  // Pressing a key
	glfwSetCharCallback(_window, char_callback);						  // Outputing a text char (for ImGui)
	glfwSetMouseButtonCallback(_window, mouse_button_callback);		  // Clicking the mouse buttons
	glfwSetCursorPosCallback(_window, cursor_pos_callback);			  // Moving the cursor
	glfwSetScrollCallback(_window, scroll_callback);					  // Scrolling
	glfwSetJoystickCallback(joystick_callback);						  // Joystick
	glfwSetWindowIconifyCallback(_window, iconify_callback);			  // Window minimization
	glfwSwapInterval(_config.vsync ? (_config.rate == 30 ? 2 : 1) : 0); // 60 FPS V-sync

	setupImGui();

	// Check the window position and size (if we are on a screen smaller than the initial size).
	glfwGetWindowPos(_window, &_config.windowFrame[0], &_config.windowFrame[1]);
	glfwGetWindowSize(_window, &_config.windowFrame[2], &_config.windowFrame[3]);

	// On HiDPI screens, we have to consider the internal resolution for all framebuffers size.
	int width, height;
	glfwGetFramebufferSize(_window, &width, &height);
	config.screenResolution = glm::vec2(width, height);

	// Compute point density by computing the ratio.
	const float screenDensity = float(width) / float(_config.windowFrame[2]);
	Input::manager().densityEvent(screenDensity);

	// Update the resolution.
	Input::manager().resizeEvent(width, height);
	Framebuffer::backbufferResized(width, height);
}

void Window::perform(Action action) {
	switch(action) {
		case Action::Quit:
			glfwSetWindowShouldClose(_window, GLFW_TRUE);
			break;
		case Action::Vsync: {
			if(_config.vsync) {
				glfwSwapInterval(0);
			} else {
				glfwSwapInterval(_config.rate == 30 ? 2 : 1);
			}
			_config.vsync = !_config.vsync;
			break;
		}
		case Action::Fullscreen: {
			// Are we currently fullscreen?
			const bool fullscreen = glfwGetWindowMonitor(_window) != nullptr;

			if(fullscreen) {
				// Restore the window position and size.
				glfwSetWindowMonitor(_window, nullptr, _config.windowFrame[0], _config.windowFrame[1], _config.windowFrame[2], _config.windowFrame[3], 0);
				// Check the window position and size (if we are on a screen smaller than the initial size).
				glfwGetWindowPos(_window, &_config.windowFrame[0], &_config.windowFrame[1]);
				glfwGetWindowSize(_window, &_config.windowFrame[2], &_config.windowFrame[3]);
			} else {
				// Backup the window current frame.
				glfwGetWindowPos(_window, &_config.windowFrame[0], &_config.windowFrame[1]);
				glfwGetWindowSize(_window, &_config.windowFrame[2], &_config.windowFrame[3]);
				// Move to fullscreen on the primary monitor.
				GLFWmonitor * monitor	= glfwGetPrimaryMonitor();
				const GLFWvidmode * mode = glfwGetVideoMode(monitor);
				glfwSetWindowMonitor(_window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
			}
			_config.fullscreen = !fullscreen;
			// On some hardware, V-sync options can be lost.
			glfwSwapInterval(_config.vsync ? (_config.rate == 30 ? 2 : 1) : 0);

			// On HiDPI screens, we have to consider the internal resolution for all framebuffers size.
			int width, height;
			glfwGetFramebufferSize(_window, &width, &height);
			_config.screenResolution = glm::vec2(width, height);

			int wwidth, hheight;
			glfwGetWindowSize(_window, &wwidth, &hheight);
			// Compute point density by computing the ratio.
			const float screenDensity = float(width) / float(wwidth);
			Input::manager().densityEvent(screenDensity);

			// Update the resolution.
			Input::manager().resizeEvent(width, height);
		} break;
		default:
			break;
	}
}

bool Window::nextFrame() {
	if(_frameStarted){
		// Render the interface.
		ImGui::Render();
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
		//Display the result for the current rendering loop.
		glfwSwapBuffers(_window);
	}
	// Update events (inputs,...).
	Input::manager().update();
	// Handle quitting.
	if(_allowEscape && Input::manager().pressed(Input::Key::Escape)) {
		perform(Action::Quit);
	}
	// Check if the backbuffer was resized.
	if(Input::manager().resized()){
		const uint w = uint(Input::manager().size()[0]);
		const uint h = uint(Input::manager().size()[1]);
		Framebuffer::backbufferResized(w, h);
	}
	// Start new GUI frame.
	ImGui_ImplOpenGL3_NewFrame();
	ImGui_ImplGlfw_NewFrame();
	ImGui::NewFrame();
	_frameStarted = true;
	return !glfwWindowShouldClose(_window);
}

Window::~Window() {
	// Make sure rendering is done.
	if(_frameStarted){
		ImGui::EndFrame();
	}
	GLUtilities::sync();
	// Clean the interface.
	ImGui_ImplOpenGL3_Shutdown();
	ImGui_ImplGlfw_Shutdown();
	ImGui::DestroyContext();
	// Close GL context and any other GLFW resources.
	glfwDestroyWindow(_window);
	glfwTerminate();
}

void Window::setupImGui() {
	ImGui::CreateContext();
	ImGuiIO & io = ImGui::GetIO();
	(void)io;
	ImGui_ImplGlfw_InitForOpenGL(_window, false);
	ImGui_ImplOpenGL3_Init("#version 400");

	// Customize the style.
	ImGui::StyleColorsDark();
	ImGuiStyle & style = ImGui::GetStyle();
	// Colors.
	ImVec4 * colors						  = style.Colors;
	colors[ImGuiCol_WindowBg]			  = ImVec4(0.04f, 0.04f, 0.04f, 0.94f);
	colors[ImGuiCol_FrameBg]			  = ImVec4(0.16f, 0.16f, 0.16f, 0.54f);
	colors[ImGuiCol_FrameBgHovered]		  = ImVec4(0.36f, 0.36f, 0.36f, 0.40f);
	colors[ImGuiCol_FrameBgActive]		  = ImVec4(0.54f, 0.54f, 0.54f, 0.67f);
	colors[ImGuiCol_TitleBgActive]		  = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
	colors[ImGuiCol_ScrollbarGrab]		  = ImVec4(0.17f, 0.17f, 0.17f, 1.00f);
	colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.34f, 0.34f, 0.34f, 1.00f);
	colors[ImGuiCol_ScrollbarGrabActive]  = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
	colors[ImGuiCol_CheckMark]			  = ImVec4(0.84f, 0.84f, 0.84f, 1.00f);
	colors[ImGuiCol_SliderGrab]			  = ImVec4(0.30f, 0.30f, 0.30f, 1.00f);
	colors[ImGuiCol_SliderGrabActive]	 = ImVec4(0.64f, 0.64f, 0.64f, 1.00f);
	colors[ImGuiCol_Button]				  = ImVec4(0.68f, 0.68f, 0.68f, 0.40f);
	colors[ImGuiCol_ButtonHovered]		  = ImVec4(0.40f, 0.40f, 0.40f, 1.00f);
	colors[ImGuiCol_ButtonActive]		  = ImVec4(0.53f, 0.53f, 0.53f, 1.00f);
	colors[ImGuiCol_Header]				  = ImVec4(0.57f, 0.57f, 0.57f, 0.31f);
	colors[ImGuiCol_HeaderHovered]		  = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
	colors[ImGuiCol_HeaderActive]		  = ImVec4(0.52f, 0.52f, 0.52f, 1.00f);
	colors[ImGuiCol_Separator]			  = ImVec4(0.41f, 0.41f, 0.41f, 0.50f);
	colors[ImGuiCol_SeparatorHovered]	 = ImVec4(0.43f, 0.43f, 0.43f, 0.78f);
	colors[ImGuiCol_SeparatorActive]	  = ImVec4(0.44f, 0.44f, 0.44f, 1.00f);
	colors[ImGuiCol_ResizeGrip]			  = ImVec4(1.00f, 1.00f, 1.00f, 0.25f);
	colors[ImGuiCol_ResizeGripHovered]	= ImVec4(0.84f, 0.84f, 0.84f, 0.67f);
	colors[ImGuiCol_ResizeGripActive]	 = ImVec4(0.88f, 0.88f, 0.88f, 0.95f);
	colors[ImGuiCol_PlotLinesHovered]	 = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
	colors[ImGuiCol_PlotHistogram]		  = ImVec4(0.62f, 0.62f, 0.62f, 1.00f);
	colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
	colors[ImGuiCol_TextSelectedBg]		  = ImVec4(0.67f, 0.67f, 0.67f, 0.35f);
	colors[ImGuiCol_DragDropTarget]		  = ImVec4(0.83f, 0.83f, 0.83f, 0.90f);
	colors[ImGuiCol_NavHighlight]		  = ImVec4(0.88f, 0.88f, 0.88f, 1.00f);
	// Frames.
	style.FrameRounding		 = 5.0f;
	style.GrabRounding		 = 3.0f;
	style.WindowRounding	 = 5.0f;
	style.ScrollbarRounding  = 12.0f;
	style.ScrollbarSize		 = 12.0f;
	style.WindowTitleAlign.x = 0.5f;
	style.FramePadding.y	 = 4.0f;
	style.ItemSpacing.y		 = 3.0f;
}
<|endoftext|>


<commit_before>/*
 * This file is part of Kopete
 *
 * Copyright (C) 2009 Collabora Ltd. <info@collabora.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "plugin-manager.h"

#include "abstract-account-ui-plugin.h"
#include "abstract-account-ui.h"

#include <KDebug>
#include <KServiceTypeTrader>

PluginManager* PluginManager::s_self = 0;

PluginManager::PluginManager(QObject *parent)
 : QObject(parent)
{
    kDebug();

    // Set up the singleton instance
    s_self = this;

    loadPlugins();
}

PluginManager::~PluginManager()
{
    kDebug();

    // Delete the singleton instance of this class
    s_self = 0;
}

PluginManager *PluginManager::instance()
{
    kDebug();

    // Construct the singleton if hasn't been already
    if (!s_self) {
        s_self = new PluginManager(0);
    }

    // Return the singleton instance of this class
    return s_self;
}

void PluginManager::loadPlugins()
{
    kDebug();
    KService::List offers = KServiceTypeTrader::self()->query("KCMTelepathyAccounts/AccountUiPlugin");

    KService::List::const_iterator iter;
    for (iter = offers.constBegin(); iter < offers.constEnd(); ++iter) {
       QString error;
       KService::Ptr service = *iter;

        KPluginFactory *factory = KPluginLoader(service->library()).factory();

        if (!factory) {
            kWarning() << "KPluginFactory could not load the plugin:" << service->library();
            continue;
        }

       AbstractAccountUiPlugin *plugin = factory->create<AbstractAccountUiPlugin>(this);

       if (plugin) {
           kDebug() << "Loaded plugin:" << service->name();
           m_plugins.append(plugin);
       } else {
           kDebug() << error;
       }
    }
}

AbstractAccountUi *PluginManager::accountUiForProtocol(const QString &connectionManager,
                                                       const QString &protocol,
                                                       const QString &serviceName)
{
    kDebug();

    // Loop through all the plugins seeing if they provide an AccountUi for the connection manager
    // and protocol combination we were provided with.

    foreach (AbstractAccountUiPlugin *plugin, m_plugins) {
        AbstractAccountUi *ui = plugin->accountUi(connectionManager, protocol, serviceName);

        // FIXME: Bug https://bugs.kde.org/201797 - we should check here to see which plugin
        // provides the closest match for the desired parameters in the case that more than one
        // plugin provides a UI for this protocol/cm pair.
        if (ui) {
            return ui;
        }
    }

    return 0;
}

#include "plugin-manager.moc"

<commit_msg>Fix plugin loading after renaming<commit_after>/*
 * This file is part of Kopete
 *
 * Copyright (C) 2009 Collabora Ltd. <info@collabora.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "plugin-manager.h"

#include "abstract-account-ui-plugin.h"
#include "abstract-account-ui.h"

#include <KDebug>
#include <KServiceTypeTrader>

PluginManager* PluginManager::s_self = 0;

PluginManager::PluginManager(QObject *parent)
 : QObject(parent)
{
    kDebug();

    // Set up the singleton instance
    s_self = this;

    loadPlugins();
}

PluginManager::~PluginManager()
{
    kDebug();

    // Delete the singleton instance of this class
    s_self = 0;
}

PluginManager *PluginManager::instance()
{
    kDebug();

    // Construct the singleton if hasn't been already
    if (!s_self) {
        s_self = new PluginManager(0);
    }

    // Return the singleton instance of this class
    return s_self;
}

void PluginManager::loadPlugins()
{
    kDebug();
    KService::List offers = KServiceTypeTrader::self()->query("KTpAccountsKCM/AccountUiPlugin");

    KService::List::const_iterator iter;
    for (iter = offers.constBegin(); iter < offers.constEnd(); ++iter) {
       QString error;
       KService::Ptr service = *iter;

        KPluginFactory *factory = KPluginLoader(service->library()).factory();

        if (!factory) {
            kWarning() << "KPluginFactory could not load the plugin:" << service->library();
            continue;
        }

       AbstractAccountUiPlugin *plugin = factory->create<AbstractAccountUiPlugin>(this);

       if (plugin) {
           kDebug() << "Loaded plugin:" << service->name();
           m_plugins.append(plugin);
       } else {
           kDebug() << error;
       }
    }
}

AbstractAccountUi *PluginManager::accountUiForProtocol(const QString &connectionManager,
                                                       const QString &protocol,
                                                       const QString &serviceName)
{
    kDebug();

    // Loop through all the plugins seeing if they provide an AccountUi for the connection manager
    // and protocol combination we were provided with.

    foreach (AbstractAccountUiPlugin *plugin, m_plugins) {
        AbstractAccountUi *ui = plugin->accountUi(connectionManager, protocol, serviceName);

        // FIXME: Bug https://bugs.kde.org/201797 - we should check here to see which plugin
        // provides the closest match for the desired parameters in the case that more than one
        // plugin provides a UI for this protocol/cm pair.
        if (ui) {
            return ui;
        }
    }

    return 0;
}

#include "plugin-manager.moc"

<|endoftext|>


<commit_before>// Copyright (C) 2014 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Win32/TaskSchedulerImpl.hpp>
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp>
#include <cstdlib> // std::ldiv
#include <process.h>
#include <Nazara/Core/Debug.hpp>

bool NzTaskSchedulerImpl::Initialize(unsigned int workerCount)
{
	if (s_workerCount > 0)
		return true; // Déjà initialisé

	#if NAZARA_CORE_SAFE
	if (workerCount == 0)
	{
		NazaraError("Invalid worker count ! (0)");
		return false;
	}
	#endif

	s_workerCount = workerCount;
	s_doneEvents.reset(new HANDLE[workerCount]);
	s_workers.reset(new Worker[workerCount]);
	s_workerThreads.reset(new HANDLE[workerCount]);

	// L'identifiant de chaque worker doit rester en vie jusqu'à ce que chaque thread soit correctement lancé
	std::unique_ptr<unsigned int[]> workerIDs(new unsigned int[workerCount]);

	for (unsigned int i = 0; i < workerCount; ++i)
	{
		Worker& worker = s_workers[i];
		InitializeCriticalSection(&worker.queueMutex);
		worker.wakeEvent = CreateEventA(nullptr, false, false, nullptr);
		worker.running = true;
		worker.workCount = 0;

		s_doneEvents[i] = CreateEventA(nullptr, true, false, nullptr);

		workerIDs[i] = i;
		s_workerThreads[i] = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &WorkerProc, &workerIDs[i], 0, nullptr));
	}

	// On attend que les workers se mettent en attente
	WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);

	return true;
}

bool NzTaskSchedulerImpl::IsInitialized()
{
	return s_workerCount > 0;
}

void NzTaskSchedulerImpl::Run(NzFunctor** tasks, unsigned int count)
{
	WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);

	std::ldiv_t div = std::ldiv(count, s_workerCount); // Division et modulo en une opération, y'a pas de petit profit
	for (unsigned int i = 0; i < s_workerCount; ++i)
	{
		Worker& worker = s_workers[i];
		unsigned int taskCount = (i == 0) ? div.quot + div.rem : div.quot;
		for (unsigned int j = 0; j < taskCount; ++j)
			worker.queue.push(*tasks++);

		worker.workCount = taskCount;
	}

	// On les lance une fois qu'ils sont tous initialisés (pour éviter qu'un worker ne passe en pause détectant une absence de travaux)
	for (unsigned int i = 0; i < s_workerCount; ++i)
	{
		ResetEvent(s_doneEvents[i]);
		SetEvent(s_workers[i].wakeEvent);
	}
}

void NzTaskSchedulerImpl::Uninitialize()
{
	#ifdef NAZARA_CORE_SAFE
	if (s_workerCount == 0)
	{
		NazaraError("Task scheduler is not initialized");
		return;
	}
	#endif

	for (unsigned int i = 0; i < s_workerCount; ++i)
	{
		Worker& worker = s_workers[i];
		worker.running = false;
		worker.workCount = 0;

		EnterCriticalSection(&worker.queueMutex);

		std::queue<NzFunctor*> emptyQueue;
		std::swap(worker.queue, emptyQueue); // Et on vide la queue

		LeaveCriticalSection(&worker.queueMutex);

		SetEvent(worker.wakeEvent);
	}

	WaitForMultipleObjects(s_workerCount, &s_workerThreads[0], true, INFINITE);

	for (unsigned int i = 0; i < s_workerCount; ++i)
	{
		Worker& worker = s_workers[i];
		CloseHandle(s_doneEvents[i]);
		CloseHandle(s_workerThreads[i]);
		CloseHandle(worker.wakeEvent);
		DeleteCriticalSection(&worker.queueMutex);
	}

	s_doneEvents.reset();
	s_workers.reset();
	s_workerThreads.reset();
	s_workerCount = 0;
}

void NzTaskSchedulerImpl::WaitForTasks()
{
	#ifdef NAZARA_CORE_SAFE
	if (s_workerCount == 0)
	{
		NazaraError("Task scheduler is not initialized");
		return;
	}
	#endif

	WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
}

NzFunctor* NzTaskSchedulerImpl::StealTask(unsigned int workerID)
{
	bool shouldRetry;
	do
	{
		shouldRetry = false;
		for (unsigned int i = 0; i < s_workerCount; ++i)
		{
			if (i == workerID)
				continue;

			Worker& worker = s_workers[i];

			if (worker.workCount > 0)
			{
				NzFunctor* task;
				if (TryEnterCriticalSection(&worker.queueMutex))
				{
					if (!worker.queue.empty())
					{
						task = worker.queue.front();
						worker.queue.pop();
						worker.workCount = worker.queue.size();
					}
					else
						task = nullptr;

					LeaveCriticalSection(&worker.queueMutex);
				}
				else
					shouldRetry = true; // Il est encore possible d'avoir un job

				if (task)
					return task;
			}
		}
	}
	while (shouldRetry);

	return nullptr;
}

unsigned int __stdcall NzTaskSchedulerImpl::WorkerProc(void* userdata)
{
	unsigned int workerID = *reinterpret_cast<unsigned int*>(userdata);
	SetEvent(s_doneEvents[workerID]);

	Worker& worker = s_workers[workerID];
	WaitForSingleObject(worker.wakeEvent, INFINITE);

	while (worker.running)
	{
		NzFunctor* task = nullptr;

		if (worker.workCount > 0) // Permet d'éviter d'entrer inutilement dans une section critique
		{
			EnterCriticalSection(&worker.queueMutex);
			if (!worker.queue.empty()) // Nécessaire car le workCount peut être tombé à zéro juste avant l'entrée dans la section critique
			{
				task = worker.queue.front();
				worker.queue.pop();
				worker.workCount = worker.queue.size();
			}
			LeaveCriticalSection(&worker.queueMutex);
		}

		if (!task)
			task = StealTask(workerID);

		if (task)
		{
			task->Run();
			delete task;
		}
		else
		{
			SetEvent(s_doneEvents[workerID]);
			WaitForSingleObject(worker.wakeEvent, INFINITE);
		}
	}

	SetEvent(s_doneEvents[workerID]); // Au cas où un thread attendrait sur WaitForTasks() pendant qu'un autre appellerait Uninitialize()

	return 0;
}

std::unique_ptr<HANDLE[]> NzTaskSchedulerImpl::s_doneEvents; // Doivent être contigus
std::unique_ptr<NzTaskSchedulerImpl::Worker[]> NzTaskSchedulerImpl::s_workers;
std::unique_ptr<HANDLE[]> NzTaskSchedulerImpl::s_workerThreads; // Doivent être contigus
unsigned int NzTaskSchedulerImpl::s_workerCount;
<commit_msg>Fixed crash in TaskScheduler Windows implementation<commit_after>// Copyright (C) 2014 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Win32/TaskSchedulerImpl.hpp>
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp>
#include <cstdlib> // std::ldiv
#include <process.h>
#include <Nazara/Core/Debug.hpp>

bool NzTaskSchedulerImpl::Initialize(unsigned int workerCount)
{
	if (s_workerCount > 0)
		return true; // Déjà initialisé

	#if NAZARA_CORE_SAFE
	if (workerCount == 0)
	{
		NazaraError("Invalid worker count ! (0)");
		return false;
	}
	#endif

	s_workerCount = workerCount;
	s_doneEvents.reset(new HANDLE[workerCount]);
	s_workers.reset(new Worker[workerCount]);
	s_workerThreads.reset(new HANDLE[workerCount]);

	// L'identifiant de chaque worker doit rester en vie jusqu'à ce que chaque thread soit correctement lancé
	std::unique_ptr<unsigned int[]> workerIDs(new unsigned int[workerCount]);

	for (unsigned int i = 0; i < workerCount; ++i)
	{
		Worker& worker = s_workers[i];
		InitializeCriticalSection(&worker.queueMutex);
		worker.wakeEvent = CreateEventW(nullptr, false, false, nullptr);
		worker.running = true;
		worker.workCount = 0;

		s_doneEvents[i] = CreateEventW(nullptr, true, false, nullptr);

		workerIDs[i] = i;
		s_workerThreads[i] = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &WorkerProc, &workerIDs[i], 0, nullptr));
	}

	// On attend que les workers se mettent en attente
	WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);

	return true;
}

bool NzTaskSchedulerImpl::IsInitialized()
{
	return s_workerCount > 0;
}

void NzTaskSchedulerImpl::Run(NzFunctor** tasks, unsigned int count)
{
	WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);

	std::ldiv_t div = std::ldiv(count, s_workerCount); // Division et modulo en une opération, y'a pas de petit profit
	for (unsigned int i = 0; i < s_workerCount; ++i)
	{
		Worker& worker = s_workers[i];
		unsigned int taskCount = (i == 0) ? div.quot + div.rem : div.quot;
		for (unsigned int j = 0; j < taskCount; ++j)
			worker.queue.push(*tasks++);

		worker.workCount = taskCount;
	}

	// On les lance une fois qu'ils sont tous initialisés (pour éviter qu'un worker ne passe en pause détectant une absence de travaux)
	for (unsigned int i = 0; i < s_workerCount; ++i)
	{
		ResetEvent(s_doneEvents[i]);
		SetEvent(s_workers[i].wakeEvent);
	}
}

void NzTaskSchedulerImpl::Uninitialize()
{
	#ifdef NAZARA_CORE_SAFE
	if (s_workerCount == 0)
	{
		NazaraError("Task scheduler is not initialized");
		return;
	}
	#endif

	for (unsigned int i = 0; i < s_workerCount; ++i)
	{
		Worker& worker = s_workers[i];
		worker.running = false;
		worker.workCount = 0;

		EnterCriticalSection(&worker.queueMutex);

		std::queue<NzFunctor*> emptyQueue;
		std::swap(worker.queue, emptyQueue); // Et on vide la queue

		LeaveCriticalSection(&worker.queueMutex);

		SetEvent(worker.wakeEvent);
	}

	WaitForMultipleObjects(s_workerCount, &s_workerThreads[0], true, INFINITE);

	for (unsigned int i = 0; i < s_workerCount; ++i)
	{
		Worker& worker = s_workers[i];
		CloseHandle(s_doneEvents[i]);
		CloseHandle(s_workerThreads[i]);
		CloseHandle(worker.wakeEvent);
		DeleteCriticalSection(&worker.queueMutex);
	}

	s_doneEvents.reset();
	s_workers.reset();
	s_workerThreads.reset();
	s_workerCount = 0;
}

void NzTaskSchedulerImpl::WaitForTasks()
{
	#ifdef NAZARA_CORE_SAFE
	if (s_workerCount == 0)
	{
		NazaraError("Task scheduler is not initialized");
		return;
	}
	#endif

	WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
}

NzFunctor* NzTaskSchedulerImpl::StealTask(unsigned int workerID)
{
	bool shouldRetry;
	do
	{
		shouldRetry = false;
		for (unsigned int i = 0; i < s_workerCount; ++i)
		{
			if (i == workerID)
				continue;

			Worker& worker = s_workers[i];

			if (worker.workCount > 0)
			{
				NzFunctor* task = nullptr;

				if (TryEnterCriticalSection(&worker.queueMutex))
				{
					if (!worker.queue.empty())
					{
						task = worker.queue.front();
						worker.queue.pop();
						worker.workCount = worker.queue.size();
					}

					LeaveCriticalSection(&worker.queueMutex);
				}
				else
					shouldRetry = true; // Il est encore possible d'avoir un job

				if (task)
					return task;
			}
		}
	}
	while (shouldRetry);

	return nullptr;
}

unsigned int __stdcall NzTaskSchedulerImpl::WorkerProc(void* userdata)
{
	unsigned int workerID = *reinterpret_cast<unsigned int*>(userdata);
	SetEvent(s_doneEvents[workerID]);

	Worker& worker = s_workers[workerID];
	WaitForSingleObject(worker.wakeEvent, INFINITE);

	while (worker.running)
	{
		NzFunctor* task = nullptr;

		if (worker.workCount > 0) // Permet d'éviter d'entrer inutilement dans une section critique
		{
			EnterCriticalSection(&worker.queueMutex);
			if (!worker.queue.empty()) // Nécessaire car le workCount peut être tombé à zéro juste avant l'entrée dans la section critique
			{
				task = worker.queue.front();
				worker.queue.pop();
				worker.workCount = worker.queue.size();
			}
			LeaveCriticalSection(&worker.queueMutex);
		}

		if (!task)
			task = StealTask(workerID);

		if (task)
		{
			task->Run();
			delete task;
		}
		else
		{
			SetEvent(s_doneEvents[workerID]);
			WaitForSingleObject(worker.wakeEvent, INFINITE);
		}
	}

	SetEvent(s_doneEvents[workerID]); // Au cas où un thread attendrait sur WaitForTasks() pendant qu'un autre appellerait Uninitialize()

	return 0;
}

std::unique_ptr<HANDLE[]> NzTaskSchedulerImpl::s_doneEvents; // Doivent être contigus
std::unique_ptr<NzTaskSchedulerImpl::Worker[]> NzTaskSchedulerImpl::s_workers;
std::unique_ptr<HANDLE[]> NzTaskSchedulerImpl::s_workerThreads; // Doivent être contigus
unsigned int NzTaskSchedulerImpl::s_workerCount;
<|endoftext|>


<commit_before>#include "AssetNameMap.hpp"
#include "athena/Compression.hpp"
#include "athena/MemoryReader.hpp"

extern "C" const uint8_t ASSET_NAME_MP32[];
extern "C" const size_t ASSET_NAME_MP32_SZ;
extern "C" const size_t ASSET_NAME_MP32_DECOMPRESSED_SZ;
extern "C" const uint8_t ASSET_NAME_MP64[];
extern "C" const size_t ASSET_NAME_MP64_SZ;
extern "C" const size_t ASSET_NAME_MP64_DECOMPRESSED_SZ;

namespace DataSpec::AssetNameMap {
logvisor::Module Log("AssetNameMap");

struct SAsset {
  std::string name;
  std::string directory;
  hecl::FourCC type;
  SAsset() = default;
  SAsset(const hecl::FourCC& typeIn, athena::io::IStreamReader& in) : type(typeIn) {
    uint32_t nameLen = in.readUint32Big();
    name = in.readString(nameLen);
    uint32_t dirLen = in.readUint32Big();
    directory = in.readString(dirLen);
  }
};

static std::unordered_map<uint64_t, SAsset> g_AssetNameMap;
static bool g_AssetNameMapInit = false;

void LoadAssetMap(athena::io::MemoryReader& ar) {
  if (!ar.hasError()) {
    hecl::FourCC magic;
    if (ar.length() >= 4)
      ar.readBytesToBuf(&magic, 4);
    if (magic != FOURCC('AIDM'))
      Log.report(logvisor::Warning,
                 FMT_STRING(_SYS_STR("Unable to load asset map; Assets will not have proper filenames for most files.")));
    else {
      uint32_t assetCount = ar.readUint32Big();
      g_AssetNameMap.reserve(assetCount);
      for (uint32_t i = 0; i < assetCount; ++i) {
        hecl::FourCC type;
        ar.readBytesToBuf(&type, 4);
        uint64_t id = ar.readUint64Big();
        g_AssetNameMap[id] = SAsset(type, ar);
      }
    }
  }
}

void InitAssetNameMap() {
  if (g_AssetNameMapInit)
    return;

  Log.report(logvisor::Info, FMT_STRING("Initializing asset name database..."));

  /* First load the 32bit map for MP1/2 */
  if (ASSET_NAME_MP32_DECOMPRESSED_SZ) {
    auto decompressed = new uint8_t[ASSET_NAME_MP32_DECOMPRESSED_SZ];
    athena::io::Compression::decompressZlib(ASSET_NAME_MP32, ASSET_NAME_MP32_SZ, decompressed,
                                            ASSET_NAME_MP32_DECOMPRESSED_SZ);
    athena::io::MemoryReader ar(decompressed, ASSET_NAME_MP32_DECOMPRESSED_SZ);
    LoadAssetMap(ar);
    delete[](decompressed);
  } else {
    Log.report(logvisor::Warning,
               fmt(_SYS_STR("AssetNameMap32 unavailable; Assets will not have proper filenames for most files.")));
  }
  /* Now load the 64bit map for MP3 */
  if (ASSET_NAME_MP64_DECOMPRESSED_SZ) {
    auto decompressed = new uint8_t[ASSET_NAME_MP64_DECOMPRESSED_SZ];
    athena::io::Compression::decompressZlib(ASSET_NAME_MP64, ASSET_NAME_MP64_SZ, decompressed,
                                            ASSET_NAME_MP64_DECOMPRESSED_SZ);
    athena::io::MemoryReader ar(decompressed, ASSET_NAME_MP64_DECOMPRESSED_SZ);
    LoadAssetMap(ar);
    delete[](decompressed);
  } else {
    Log.report(logvisor::Warning,
               fmt(_SYS_STR("AssetNameMap64 unavailable; Assets will not have proper filenames for most files.")));
  }
  g_AssetNameMapInit = true;
}

const std::string* TranslateIdToName(const UniqueID32& id) {
  if (g_AssetNameMap.find(id.toUint64()) == g_AssetNameMap.cend())
    return nullptr;

  return &g_AssetNameMap[id.toUint64()].name;
}

} // namespace DataSpec::AssetNameMap
<commit_msg>AssetNameMap: Fix fmt strings<commit_after>#include "AssetNameMap.hpp"
#include "athena/Compression.hpp"
#include "athena/MemoryReader.hpp"

extern "C" const uint8_t ASSET_NAME_MP32[];
extern "C" const size_t ASSET_NAME_MP32_SZ;
extern "C" const size_t ASSET_NAME_MP32_DECOMPRESSED_SZ;
extern "C" const uint8_t ASSET_NAME_MP64[];
extern "C" const size_t ASSET_NAME_MP64_SZ;
extern "C" const size_t ASSET_NAME_MP64_DECOMPRESSED_SZ;

namespace DataSpec::AssetNameMap {
logvisor::Module Log("AssetNameMap");

struct SAsset {
  std::string name;
  std::string directory;
  hecl::FourCC type;
  SAsset() = default;
  SAsset(const hecl::FourCC& typeIn, athena::io::IStreamReader& in) : type(typeIn) {
    uint32_t nameLen = in.readUint32Big();
    name = in.readString(nameLen);
    uint32_t dirLen = in.readUint32Big();
    directory = in.readString(dirLen);
  }
};

static std::unordered_map<uint64_t, SAsset> g_AssetNameMap;
static bool g_AssetNameMapInit = false;

void LoadAssetMap(athena::io::MemoryReader& ar) {
  if (!ar.hasError()) {
    hecl::FourCC magic;
    if (ar.length() >= 4)
      ar.readBytesToBuf(&magic, 4);
    if (magic != FOURCC('AIDM'))
      Log.report(logvisor::Warning,
                 FMT_STRING(_SYS_STR("Unable to load asset map; Assets will not have proper filenames for most files.")));
    else {
      uint32_t assetCount = ar.readUint32Big();
      g_AssetNameMap.reserve(assetCount);
      for (uint32_t i = 0; i < assetCount; ++i) {
        hecl::FourCC type;
        ar.readBytesToBuf(&type, 4);
        uint64_t id = ar.readUint64Big();
        g_AssetNameMap[id] = SAsset(type, ar);
      }
    }
  }
}

void InitAssetNameMap() {
  if (g_AssetNameMapInit)
    return;

  Log.report(logvisor::Info, FMT_STRING("Initializing asset name database..."));

  /* First load the 32bit map for MP1/2 */
  if (ASSET_NAME_MP32_DECOMPRESSED_SZ != 0u) {
    auto* decompressed = new uint8_t[ASSET_NAME_MP32_DECOMPRESSED_SZ];
    athena::io::Compression::decompressZlib(ASSET_NAME_MP32, ASSET_NAME_MP32_SZ, decompressed,
                                            ASSET_NAME_MP32_DECOMPRESSED_SZ);
    athena::io::MemoryReader ar(decompressed, ASSET_NAME_MP32_DECOMPRESSED_SZ);
    LoadAssetMap(ar);
    delete[](decompressed);
  } else {
    Log.report(logvisor::Warning,
               FMT_STRING(_SYS_STR("AssetNameMap32 unavailable; Assets will not have proper filenames for most files.")));
  }
  /* Now load the 64bit map for MP3 */
  if (ASSET_NAME_MP64_DECOMPRESSED_SZ != 0u) {
    auto* decompressed = new uint8_t[ASSET_NAME_MP64_DECOMPRESSED_SZ];
    athena::io::Compression::decompressZlib(ASSET_NAME_MP64, ASSET_NAME_MP64_SZ, decompressed,
                                            ASSET_NAME_MP64_DECOMPRESSED_SZ);
    athena::io::MemoryReader ar(decompressed, ASSET_NAME_MP64_DECOMPRESSED_SZ);
    LoadAssetMap(ar);
    delete[](decompressed);
  } else {
    Log.report(logvisor::Warning,
               FMT_STRING(_SYS_STR("AssetNameMap64 unavailable; Assets will not have proper filenames for most files.")));
  }
  g_AssetNameMapInit = true;
}

const std::string* TranslateIdToName(const UniqueID32& id) {
  if (g_AssetNameMap.find(id.toUint64()) == g_AssetNameMap.cend())
    return nullptr;

  return &g_AssetNameMap[id.toUint64()].name;
}

} // namespace DataSpec::AssetNameMap
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    MultiplexOut.cpp
  \author  Jens Krueger
           SCI Institute
           University of Utah
  \date    September 2008
*/

#include "MultiplexOut.h"

#ifdef WIN32
  #include <windows.h>
  // undef stupid windows defines to max and min
  #ifdef max
  #undef max
  #endif

  #ifdef min
  #undef min
  #endif
#endif

#include <stdarg.h>
#include <algorithm>

#include <fstream>
using namespace std;

MultiplexOut::~MultiplexOut() {
  for (size_t i = 0;i<m_vpDebugger.size();i++) {
    m_vpDebugger[i]->Message(_func_, "(MultiplexOut::~MultiplexOut): Shutting down");
    delete m_vpDebugger[i];
  }
}

void MultiplexOut::AddDebugOut(AbstrDebugOut* pDebugger) {
  m_vpDebugger.push_back(pDebugger);
  pDebugger->Message(_func_,"Operating as part of a multiplexed debug out now.");
}

void MultiplexOut::RemoveDebugOut(AbstrDebugOut* pDebugger) {
  std::vector<AbstrDebugOut*>::iterator del;

  del = std::find(m_vpDebugger.begin(), m_vpDebugger.end(), pDebugger);

  if(del != m_vpDebugger.end()) {
    delete *del;
    m_vpDebugger.erase(del);
  }
}

void MultiplexOut::printf(const char* format, ...) const
{
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif

  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->printf(buff);
}

void MultiplexOut::Message(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Message(source,buff);
}

void MultiplexOut::Warning(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Warning(source,buff);
}

void MultiplexOut::Error(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Error(source,buff);
}

void MultiplexOut::SetShowMessages(bool bShowMessages) {
  AbstrDebugOut::SetShowMessages(bShowMessages);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowMessages(bShowMessages);
}

void MultiplexOut::SetShowWarnings(bool bShowWarnings) {
  AbstrDebugOut::SetShowWarnings(bShowWarnings);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowWarnings(bShowWarnings);
}

void MultiplexOut::SetShowErrors(bool bShowErrors) {
  AbstrDebugOut::SetShowErrors(bShowErrors);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowErrors(bShowErrors);
}

void MultiplexOut::SetShowOther(bool bShowOther) {
  AbstrDebugOut::SetShowOther(bShowOther);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowOther(bShowOther);
}

template <class T>
struct deleter : std::unary_function<T, void> {
  void operator()(T* p) const {
    delete p;
  }
};

void MultiplexOut::clear()
{
  std::for_each(m_vpDebugger.begin(), m_vpDebugger.end(),
                deleter<AbstrDebugOut>());
  m_vpDebugger.clear();
}
<commit_msg>Add missing include.<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    MultiplexOut.cpp
  \author  Jens Krueger
           SCI Institute
           University of Utah
  \date    September 2008
*/

#include <functional>
#include "MultiplexOut.h"

#ifdef WIN32
  #include <windows.h>
  // undef stupid windows defines to max and min
  #ifdef max
  #undef max
  #endif

  #ifdef min
  #undef min
  #endif
#endif

#include <stdarg.h>
#include <algorithm>

#include <fstream>
using namespace std;

MultiplexOut::~MultiplexOut() {
  for (size_t i = 0;i<m_vpDebugger.size();i++) {
    m_vpDebugger[i]->Message(_func_, "(MultiplexOut::~MultiplexOut): Shutting down");
    delete m_vpDebugger[i];
  }
}

void MultiplexOut::AddDebugOut(AbstrDebugOut* pDebugger) {
  m_vpDebugger.push_back(pDebugger);
  pDebugger->Message(_func_,"Operating as part of a multiplexed debug out now.");
}

void MultiplexOut::RemoveDebugOut(AbstrDebugOut* pDebugger) {
  std::vector<AbstrDebugOut*>::iterator del;

  del = std::find(m_vpDebugger.begin(), m_vpDebugger.end(), pDebugger);

  if(del != m_vpDebugger.end()) {
    delete *del;
    m_vpDebugger.erase(del);
  }
}

void MultiplexOut::printf(const char* format, ...) const
{
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif

  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->printf(buff);
}

void MultiplexOut::Message(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Message(source,buff);
}

void MultiplexOut::Warning(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Warning(source,buff);
}

void MultiplexOut::Error(const char* source, const char* format, ...) {
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->Error(source,buff);
}

void MultiplexOut::SetShowMessages(bool bShowMessages) {
  AbstrDebugOut::SetShowMessages(bShowMessages);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowMessages(bShowMessages);
}

void MultiplexOut::SetShowWarnings(bool bShowWarnings) {
  AbstrDebugOut::SetShowWarnings(bShowWarnings);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowWarnings(bShowWarnings);
}

void MultiplexOut::SetShowErrors(bool bShowErrors) {
  AbstrDebugOut::SetShowErrors(bShowErrors);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowErrors(bShowErrors);
}

void MultiplexOut::SetShowOther(bool bShowOther) {
  AbstrDebugOut::SetShowOther(bShowOther);
  for (size_t i = 0;i<m_vpDebugger.size();i++) m_vpDebugger[i]->SetShowOther(bShowOther);
}

template <class T>
struct deleter : std::unary_function<T, void> {
  void operator()(T* p) const {
    delete p;
  }
};

void MultiplexOut::clear()
{
  std::for_each(m_vpDebugger.begin(), m_vpDebugger.end(),
                deleter<AbstrDebugOut>());
  m_vpDebugger.clear();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2010 Martin Schreiber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sbndengine/iSbndEngine.hpp"
#include "../cGame.hpp"
#include "Player.hpp"
#include <iostream>

/*
#if defined(WIN32) || defined(_WIN32)
	#include <stdlib.h>
	#include <io.h>
#else
	#include <unistd.h>
#endif
*/

#include <stdio.h>
#include <sstream>

class GameApplication : public
		iApplication
{
	CGame *cGame;

	// gravitation activated / deactivated
	bool gravitation_active;

	// use absolute mouse positions for motion
	bool mouse_absolute_motion;

	// output information about gui keystrokes
	bool output_gui_key_stroke_information;

	// main engine
	iEngine engine;

	// storage for the character of the game
	struct
	{
		iRef<iObject> object;
		iRef<iPhysicsObject> physics_object;
		iRef<iGraphicsObject> graphics_object;
	} character;

	Player *player;
	cCamera3rdPerson player_camera;

	/**
	 * different kinds of materials (so far only colors are supported)
	 */
	struct
	{
		iRef<iGraphicsMaterial> whiteMaterial;
		iRef<iGraphicsMaterial> blackMaterial;
		iRef<iGraphicsMaterial> playerMaterial;
	} materials;

	/**
	 * vector containing the movement velocity of the player relative to the current view
	 */
	CVector<3,float> playerVelocity;

public:
	GameApplication()	:
		gravitation_active(true),
		mouse_absolute_motion(false),
		output_gui_key_stroke_information(true)

	{
		engine.run(this);
	}

	/**
	 * reset the players state
	 */
	void resetPlayer()
	{
		player->reset();
	}

	/**
	 * setup materials
	 */
	void setupMaterials()
	{
		/*
		 * setup white & black materials for drag&drop functionality
		 */
		materials.whiteMaterial = new iGraphicsMaterial;
		materials.whiteMaterial->setColor(iColorRGBA(1.0, 1.0, 1.0));

		materials.blackMaterial = new iGraphicsMaterial;
		materials.blackMaterial->setColor(iColorRGBA(0.0, 0.0, 0.0));

		/*
		 * setup player material
		 */
		materials.playerMaterial = new iGraphicsMaterial;
		materials.playerMaterial->setColor(iColorRGBA(0.0, 0.0, 0.0));
	}

	/**
	 * setup the scene with the mouse specific objects (mouse ball, object attached ball, etc.)
	 */
	void setupSceneMouse()
	{
	}

	/**
	 * enable gravitation in physics engine
	 */
	void enableGravitation()
	{
		engine.physics.setGravitation(CVector<3,float>(0, -9.81f, 0));
	}

	/**
	 * disable gravitation in physics engine
	 */
	void disableGravitation()
	{
		engine.physics.setGravitation(CVector<3,float>(0, 0, 0));
	}

	/*
	 * Sets up gravity, the character and the game scene
	 */
	void setupWorld()
	{
		// clear existing data
		engine.clear();

		// enable gravity
		enableGravitation();

		setupMaterials();

		// setup the game scene
		cGame->setupGameScene();
		setupCharacter();

		engine.updateObjectModelMatrices();
	}

	void setupCharacter()
	{
		iRef<cObjectFactoryBox> box_factory = new cObjectFactoryBox(1, 1, 1);

		character.object = new iObject("character");
		character.object->createFromFactory(*box_factory);
		character.graphics_object = new iGraphicsObject(character.object, materials.playerMaterial);
		engine.graphics.addObject(character.graphics_object);
		engine.addObject(*character.object);
		character.physics_object = new iPhysicsObject(*character.object);
		engine.physics.addObject(character.physics_object);

		player = new Player(character.physics_object, player_camera, engine);
	}

	/*
	 * this method is called by the engine if a frame should be drawn
	 */
	void drawFrame()
	{
		this->player->move();

		player_camera.update(player->getPhysicsObject());
		player_camera.frustum(-1.5f, 1.5f, -1.5f * engine.window.aspect_ratio, 1.5f * engine.window.aspect_ratio, 1, 100);

		engine.window.setTitle("THIS GAME IS SO MUCH FUN!!1");

		/*
		 * PHYSICS: do one simulation step
		 */
		engine.physics.simulationTimestep(engine.time.elapsed_seconds);

		/*
		 * GRAPHICS: draw the objects
		 */
		engine.graphics.drawFrame(player_camera);

		/*
		 * output some help information
		 */
		if (output_gui_key_stroke_information)
		{
			int pos_y = 10+14;
			engine.text.printfxy((float)10, (float)pos_y, "Press [h] to hide this information"); pos_y += 14;
			pos_y += 14;
			engine.text.printfxy((float)10, (float)pos_y, "[r]: reset player position"); pos_y += 14;
			engine.text.printfxy((float)10, (float)pos_y, "[q]: quit"); pos_y += 14;
			engine.text.printfxy((float)10, (float)pos_y, "[<-/->]: rotate camera"); pos_y += 14;
		}
	}

	/**
	 * engine callback: setup the application
	 */
	void setup()
	{
		cGame = new CGame(engine);

		setupWorld();
		resetPlayer();

		player_camera.setup(CVector<3, float> (0, 2, 3));
	}

	/**
	 * simply delete the allocated scenes
	 */
	void shutdown()
	{
		delete cGame;
	}

	/*
	 * this method is executed by the engine if a key was pressed
	 */
	void keyPressed(int key)
	{
		switch(key)
		{
			// General keys
			case 'q':	case 'Q':	engine.exit();	break;
			case 'h':	output_gui_key_stroke_information = !output_gui_key_stroke_information;	break;
			case 'r':	resetPlayer();	break;

			// Movement control keys
			case SBND_EVENT_KEY_UP:
			case 'w': case 'W':
				player->setVelocity(-3);
				break;
			case SBND_EVENT_KEY_DOWN:
			case 's': case 'S':
				player->setVelocity(3);
				break;
			case SBND_EVENT_KEY_LEFT:
			case 'a': case 'A':
				player->setAngularVelocity(2);
				break;
			case SBND_EVENT_KEY_RIGHT:
			case 'd': case 'D':
				player->setAngularVelocity(-2);
				break;
			case ' ':
				player->jump();
				break;
		}
	}

	/*
	 * this method is called by the engine if a key was released
	 */
	void keyReleased(int key)
	{
		switch(key)
		{
			case SBND_EVENT_KEY_UP:
			case 'w': case 'W':
			case SBND_EVENT_KEY_DOWN:
			case 's': case 'S':
				player->setVelocity(0);
				break;
			case SBND_EVENT_KEY_LEFT:
			case 'a': case 'A':
			case SBND_EVENT_KEY_RIGHT:
			case 'd': case 'D':
				player->setAngularVelocity(0);
				break;
		}
	}
};
<commit_msg>Keys that are held now are stored in a vector.<commit_after>/*
 * Copyright 2010 Martin Schreiber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sbndengine/iSbndEngine.hpp"
#include "../cGame.hpp"
#include "Player.hpp"
#include <iostream>

/*
#if defined(WIN32) || defined(_WIN32)
	#include <stdlib.h>
	#include <io.h>
#else
	#include <unistd.h>
#endif
*/

#include <stdio.h>
#include <sstream>
#include <vector>
#include <algorithm>

class GameApplication : public
		iApplication
{
	CGame *cGame;

	// gravitation activated / deactivated
	bool gravitation_active;

	// use absolute mouse positions for motion
	bool mouse_absolute_motion;

	// output information about gui keystrokes
	bool output_gui_key_stroke_information;

	// main engine
	iEngine engine;

	std::vector<int> held_keys;

	// storage for the character of the game
	struct
	{
		iRef<iObject> object;
		iRef<iPhysicsObject> physics_object;
		iRef<iGraphicsObject> graphics_object;
	} character;

	Player *player;
	cCamera3rdPerson player_camera;

	/**
	 * different kinds of materials (so far only colors are supported)
	 */
	struct
	{
		iRef<iGraphicsMaterial> whiteMaterial;
		iRef<iGraphicsMaterial> blackMaterial;
		iRef<iGraphicsMaterial> playerMaterial;
	} materials;

	/**
	 * vector containing the movement velocity of the player relative to the current view
	 */
	CVector<3,float> playerVelocity;

public:
	GameApplication()	:
		gravitation_active(true),
		mouse_absolute_motion(false),
		output_gui_key_stroke_information(true)

	{
		engine.run(this);
	}

	/**
	 * reset the players state
	 */
	void resetPlayer()
	{
		player->reset();
	}

	/**
	 * setup materials
	 */
	void setupMaterials()
	{
		/*
		 * setup white & black materials for drag&drop functionality
		 */
		materials.whiteMaterial = new iGraphicsMaterial;
		materials.whiteMaterial->setColor(iColorRGBA(1.0, 1.0, 1.0));

		materials.blackMaterial = new iGraphicsMaterial;
		materials.blackMaterial->setColor(iColorRGBA(0.0, 0.0, 0.0));

		/*
		 * setup player material
		 */
		materials.playerMaterial = new iGraphicsMaterial;
		materials.playerMaterial->setColor(iColorRGBA(0.0, 0.0, 0.0));
	}

	/**
	 * setup the scene with the mouse specific objects (mouse ball, object attached ball, etc.)
	 */
	void setupSceneMouse()
	{
	}

	/**
	 * enable gravitation in physics engine
	 */
	void enableGravitation()
	{
		engine.physics.setGravitation(CVector<3,float>(0, -9.81f, 0));
	}

	/**
	 * disable gravitation in physics engine
	 */
	void disableGravitation()
	{
		engine.physics.setGravitation(CVector<3,float>(0, 0, 0));
	}

	/*
	 * Sets up gravity, the character and the game scene
	 */
	void setupWorld()
	{
		// clear existing data
		engine.clear();

		// enable gravity
		enableGravitation();

		setupMaterials();

		// setup the game scene
		cGame->setupGameScene();
		setupCharacter();

		engine.updateObjectModelMatrices();
	}

	void setupCharacter()
	{
		iRef<cObjectFactoryBox> box_factory = new cObjectFactoryBox(1, 1, 1);

		character.object = new iObject("character");
		character.object->createFromFactory(*box_factory);
		character.graphics_object = new iGraphicsObject(character.object, materials.playerMaterial);
		engine.graphics.addObject(character.graphics_object);
		engine.addObject(*character.object);
		character.physics_object = new iPhysicsObject(*character.object);
		engine.physics.addObject(character.physics_object);

		player = new Player(character.physics_object, player_camera, engine);
	}

	/*
	 * this method is called by the engine if a frame should be drawn
	 */
	void drawFrame()
	{
		this->player->move();

		player_camera.update(player->getPhysicsObject());
		player_camera.frustum(-1.5f, 1.5f, -1.5f * engine.window.aspect_ratio, 1.5f * engine.window.aspect_ratio, 1, 100);

		engine.window.setTitle("THIS GAME IS SO MUCH FUN!!1");

		/*
		 * PHYSICS: do one simulation step
		 */
		engine.physics.simulationTimestep(engine.time.elapsed_seconds);

		/*
		 * GRAPHICS: draw the objects
		 */
		engine.graphics.drawFrame(player_camera);

		/*
		 * output some help information
		 */
		if (output_gui_key_stroke_information)
		{
			int pos_y = 10+14;
			engine.text.printfxy((float)10, (float)pos_y, "Press [h] to hide this information"); pos_y += 14;
			pos_y += 14;
			engine.text.printfxy((float)10, (float)pos_y, "[r]: reset player position"); pos_y += 14;
			engine.text.printfxy((float)10, (float)pos_y, "[q]: quit"); pos_y += 14;
			engine.text.printfxy((float)10, (float)pos_y, "[<-/->]: rotate camera"); pos_y += 14;
		}
	}

	/**
	 * engine callback: setup the application
	 */
	void setup()
	{
		cGame = new CGame(engine);

		setupWorld();
		resetPlayer();

		player_camera.setup(CVector<3, float> (0, 2, 3));
	}

	/**
	 * simply delete the allocated scenes
	 */
	void shutdown()
	{
		delete cGame;
	}

	/*
	 * this method is executed by the engine if a key was pressed
	 */
	void keyPressed(int key)
	{
		held_keys.push_back(key);
		switch(key)
		{
			// General keys
			case 'q':	case 'Q':	engine.exit();	break;
			case 'h':	output_gui_key_stroke_information = !output_gui_key_stroke_information;	break;
			case 'r':	resetPlayer();	break;

			// Movement control keys
			case SBND_EVENT_KEY_UP:
			case 'w': case 'W':
				player->setVelocity(-3);
				break;
			case SBND_EVENT_KEY_DOWN:
			case 's': case 'S':
				player->setVelocity(3);
				break;
			case SBND_EVENT_KEY_LEFT:
			case 'a': case 'A':
				player->setAngularVelocity(2);
				break;
			case SBND_EVENT_KEY_RIGHT:
			case 'd': case 'D':
				player->setAngularVelocity(-2);
				break;
			case ' ':
				player->jump();
				break;
		}
	}

	/*
	 * this method is called by the engine if a key was released
	 */
	void keyReleased(int key)
	{

		std::vector<int>::iterator element = std::find(held_keys.begin(), held_keys.end(), key);
		if (element != held_keys.end()) {
			held_keys.erase(element);
		}

		switch(key)
		{
			case SBND_EVENT_KEY_UP:
			case 'w': case 'W':
			case SBND_EVENT_KEY_DOWN:
			case 's': case 'S':
				player->setVelocity(0);
				break;
			case SBND_EVENT_KEY_LEFT:
			case 'a': case 'A':
			case SBND_EVENT_KEY_RIGHT:
			case 'd': case 'D':
				player->setAngularVelocity(0);
				break;
		}
	}
};
<|endoftext|>