// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #include #if defined(NAZARA_PLATFORM_WINDOWS) #include #elif defined(NAZARA_PLATFORM_LINUX) #include #else #error Lack of implementation: Window #endif #include namespace { NzWindow* fullscreenWindow = nullptr; } NzWindow::NzWindow() : #if NAZARA_UTILITY_THREADED_WINDOW m_impl(nullptr), m_eventListener(true), m_waitForEvent(false) #else m_impl(nullptr) #endif { } NzWindow::NzWindow(NzVideoMode mode, const NzString& title, nzUInt32 style) : #if NAZARA_UTILITY_THREADED_WINDOW m_impl(nullptr), m_eventListener(true), m_waitForEvent(false) #else m_impl(nullptr) #endif { NzErrorFlags flags(nzErrorFlag_ThrowException, true); Create(mode, title, style); } NzWindow::NzWindow(NzWindowHandle handle) : #if NAZARA_UTILITY_THREADED_WINDOW m_impl(nullptr), m_eventListener(true), m_waitForEvent(false) #else m_impl(nullptr) #endif { NzErrorFlags flags(nzErrorFlag_ThrowException, true); Create(handle); } NzWindow::~NzWindow() { Destroy(); } void NzWindow::Close() { m_closed = true; // On retarde la fermeture jusqu'au prochain IsOpen } bool NzWindow::Create(NzVideoMode mode, const NzString& title, nzUInt32 style) { // Si la fenêtre est déjà ouverte, nous conservons sa position bool opened = IsOpen(); NzVector2i position; if (opened) position = m_impl->GetPosition(); Destroy(); // Inspiré du code de la SFML par Laurent Gomila if (style & nzWindowStyle_Fullscreen) { if (fullscreenWindow) { NazaraError("Window " + NzString::Pointer(fullscreenWindow) + " already in fullscreen mode"); style &= ~nzWindowStyle_Fullscreen; } else { if (!mode.IsFullscreenValid()) { NazaraWarning("Video mode is not fullscreen valid"); mode = NzVideoMode::GetFullscreenModes()[0]; } fullscreenWindow = this; } } else if (style & nzWindowStyle_Closable || style & nzWindowStyle_Resizable) style |= nzWindowStyle_Titlebar; m_impl = new NzWindowImpl(this); if (!m_impl->Create(mode, title, style)) { NazaraError("Failed to create window implementation"); delete m_impl; m_impl = nullptr; return false; } m_closed = false; m_ownsWindow = true; if (!OnWindowCreated()) { NazaraError("Failed to initialize window extension"); delete m_impl; m_impl = nullptr; return false; } // Paramètres par défaut m_impl->EnableKeyRepeat(true); m_impl->EnableSmoothScrolling(false); m_impl->SetCursor(nzWindowCursor_Default); m_impl->SetMaximumSize(-1, -1); m_impl->SetMinimumSize(-1, -1); m_impl->SetVisible(true); if (opened) m_impl->SetPosition(position.x, position.y); return true; } bool NzWindow::Create(NzWindowHandle handle) { Destroy(); m_impl = new NzWindowImpl(this); if (!m_impl->Create(handle)) { NazaraError("Unable to create window implementation"); delete m_impl; m_impl = nullptr; return false; } m_closed = false; m_ownsWindow = false; if (!OnWindowCreated()) { NazaraError("Failed to initialize window's derivate"); delete m_impl; m_impl = nullptr; return false; } return true; } void NzWindow::Destroy() { if (m_impl) { OnWindowDestroy(); m_impl->Destroy(); delete m_impl; m_impl = nullptr; if (fullscreenWindow == this) fullscreenWindow = nullptr; } } void NzWindow::EnableKeyRepeat(bool enable) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->EnableKeyRepeat(enable); } void NzWindow::EnableSmoothScrolling(bool enable) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->EnableSmoothScrolling(enable); } NzWindowHandle NzWindow::GetHandle() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return static_cast(0); } #endif return m_impl->GetHandle(); } unsigned int NzWindow::GetHeight() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return 0; } #endif return m_impl->GetHeight(); } NzVector2i NzWindow::GetPosition() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return NzVector2i::Zero(); } #endif return m_impl->GetPosition(); } NzVector2ui NzWindow::GetSize() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return NzVector2ui::Zero(); } #endif return m_impl->GetSize(); } nzUInt32 NzWindow::GetStyle() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return 0; } #endif return m_impl->GetStyle(); } NzString NzWindow::GetTitle() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return NzString(); } #endif return m_impl->GetTitle(); } unsigned int NzWindow::GetWidth() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return 0; } #endif return m_impl->GetWidth(); } bool NzWindow::HasFocus() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return false; } #endif return m_impl->HasFocus(); } bool NzWindow::IsOpen(bool checkClosed) { if (m_impl) { if (m_closed && checkClosed) { Destroy(); return false; } else return true; } else return false; } bool NzWindow::IsOpen() const { return m_impl != nullptr; } bool NzWindow::IsMinimized() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return false; } #endif return m_impl->IsMinimized(); } bool NzWindow::IsValid() const { return m_impl != nullptr; } bool NzWindow::IsVisible() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return false; } #endif return m_impl->IsVisible(); } bool NzWindow::PollEvent(NzEvent* event) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return false; } #endif #if NAZARA_UTILITY_THREADED_WINDOW NzLockGuard lock(m_eventMutex); #else m_impl->ProcessEvents(false); #endif if (!m_events.empty()) { if (event) *event = m_events.front(); m_events.pop(); return true; } return false; } void NzWindow::SetCursor(nzWindowCursor cursor) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetCursor(cursor); } void NzWindow::SetCursor(const NzCursor& cursor) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } if (!cursor.IsValid()) { NazaraError("Cursor is not valid"); return; } #endif m_impl->SetCursor(cursor); } void NzWindow::SetEventListener(bool listener) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif #if NAZARA_UTILITY_THREADED_WINDOW m_impl->SetEventListener(listener); if (!listener) { // On vide la pile des évènements NzLockGuard lock(m_eventMutex); while (!m_events.empty()) m_events.pop(); } #else if (m_ownsWindow) { // Inutile de transmettre l'ordre dans ce cas-là if (!listener) NazaraError("A non-threaded window needs to listen to events"); } else m_impl->SetEventListener(listener); #endif } void NzWindow::SetFocus() { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetFocus(); } void NzWindow::SetIcon(const NzIcon& icon) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } if (!icon.IsValid()) { NazaraError("Icon is not valid"); return; } #endif m_impl->SetIcon(icon); } void NzWindow::SetMaximumSize(const NzVector2i& maxSize) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetMaximumSize(maxSize.x, maxSize.y); } void NzWindow::SetMaximumSize(int width, int height) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetMaximumSize(width, height); } void NzWindow::SetMinimumSize(const NzVector2i& minSize) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetMinimumSize(minSize.x, minSize.y); } void NzWindow::SetMinimumSize(int width, int height) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetMinimumSize(width, height); } void NzWindow::SetPosition(const NzVector2i& position) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetPosition(position.x, position.y); } void NzWindow::SetPosition(int x, int y) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetPosition(x, y); } void NzWindow::SetSize(const NzVector2i& size) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetSize(size.x, size.y); } void NzWindow::SetSize(unsigned int width, unsigned int height) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetSize(width, height); } void NzWindow::SetStayOnTop(bool stayOnTop) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetStayOnTop(stayOnTop); } void NzWindow::SetTitle(const NzString& title) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetTitle(title); } void NzWindow::SetVisible(bool visible) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->SetVisible(visible); } bool NzWindow::WaitEvent(NzEvent* event) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return false; } #endif #if NAZARA_UTILITY_THREADED_WINDOW NzLockGuard lock(m_eventMutex); if (m_events.empty()) { m_waitForEvent = true; m_eventConditionMutex.Lock(); m_eventMutex.Unlock(); m_eventCondition.Wait(&m_eventConditionMutex); m_eventMutex.Lock(); m_eventConditionMutex.Unlock(); m_waitForEvent = false; } if (!m_events.empty()) { if (event) *event = m_events.front(); m_events.pop(); return true; } return false; #else while (m_events.empty()) m_impl->ProcessEvents(true); if (event) *event = m_events.front(); m_events.pop(); return true; #endif } bool NzWindow::OnWindowCreated() { return true; } void NzWindow::OnWindowDestroy() { } void NzWindow::OnWindowResized() { } void NzWindow::IgnoreNextMouseEvent(int mouseX, int mouseY) const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Window not created"); return; } #endif m_impl->IgnoreNextMouseEvent(mouseX, mouseY); } void NzWindow::PushEvent(const NzEvent& event) { #if NAZARA_UTILITY_THREADED_WINDOW m_eventMutex.Lock(); #endif m_events.push(event); if (event.type == nzEventType_Resized) OnWindowResized(); #if NAZARA_UTILITY_THREADED_WINDOW m_eventMutex.Unlock(); if (m_waitForEvent) { m_eventConditionMutex.Lock(); m_eventCondition.Signal(); m_eventConditionMutex.Unlock(); } #endif } bool NzWindow::Initialize() { return NzWindowImpl::Initialize(); } void NzWindow::Uninitialize() { NzWindowImpl::Uninitialize(); }