From 37586e72838c9418ab6b837153e2de05173469b6 Mon Sep 17 00:00:00 2001 From: Youri Hubaut Date: Sun, 27 Sep 2015 15:58:49 +0200 Subject: [PATCH] Switch from Nz prefix to namespace Nz for linux Former-commit-id: 64eeaf3c633254b04910ebd4576fd9e910002be0 --- include/Nazara/Prerequesites.hpp | 1 + include/Nazara/Renderer/OpenGL.hpp | 6 +- include/Nazara/Utility/WindowHandle.hpp | 6 +- src/Nazara/Audio/Debug/NewOverload.cpp | 8 +- src/Nazara/Core/Posix/ClockImpl.cpp | 31 +- src/Nazara/Core/Posix/ClockImpl.hpp | 9 +- .../Core/Posix/ConditionVariableImpl.cpp | 77 +- .../Core/Posix/ConditionVariableImpl.hpp | 29 +- src/Nazara/Core/Posix/DirectoryImpl.cpp | 163 +- src/Nazara/Core/Posix/DirectoryImpl.hpp | 51 +- src/Nazara/Core/Posix/DynLibImpl.cpp | 95 +- src/Nazara/Core/Posix/DynLibImpl.hpp | 28 +- src/Nazara/Core/Posix/FileImpl.cpp | 425 +-- src/Nazara/Core/Posix/FileImpl.hpp | 65 +- src/Nazara/Core/Posix/HardwareInfoImpl.cpp | 103 +- src/Nazara/Core/Posix/HardwareInfoImpl.hpp | 17 +- src/Nazara/Core/Posix/MutexImpl.cpp | 45 +- src/Nazara/Core/Posix/MutexImpl.hpp | 25 +- src/Nazara/Core/Posix/SemaphoreImpl.cpp | 113 +- src/Nazara/Core/Posix/SemaphoreImpl.hpp | 25 +- src/Nazara/Core/Posix/TaskSchedulerImpl.cpp | 339 +- src/Nazara/Core/Posix/TaskSchedulerImpl.hpp | 51 +- src/Nazara/Core/Posix/ThreadImpl.cpp | 121 +- src/Nazara/Core/Posix/ThreadImpl.hpp | 27 +- src/Nazara/Graphics/Debug/NewOverload.cpp | 8 +- .../Graphics/ForwardRenderTechnique.cpp | 2 +- src/Nazara/Lua/Debug/NewOverload.cpp | 8 +- src/Nazara/Noise/Debug/NewOverload.cpp | 8 +- src/Nazara/Physics/Debug/NewOverload.cpp | 8 +- src/Nazara/Renderer/Context.cpp | 2 +- src/Nazara/Renderer/Debug/NewOverload.cpp | 8 +- src/Nazara/Renderer/GLX/ContextImpl.cpp | 499 +-- src/Nazara/Renderer/GLX/ContextImpl.hpp | 39 +- src/Nazara/Renderer/OpenGL.cpp | 20 +- src/Nazara/Utility/Debug/NewOverload.cpp | 8 +- src/Nazara/Utility/X11/CursorImpl.cpp | 263 +- src/Nazara/Utility/X11/CursorImpl.hpp | 24 +- src/Nazara/Utility/X11/Display.cpp | 107 +- src/Nazara/Utility/X11/Display.hpp | 46 +- src/Nazara/Utility/X11/IconImpl.cpp | 211 +- src/Nazara/Utility/X11/IconImpl.hpp | 30 +- src/Nazara/Utility/X11/InputImpl.cpp | 594 ++-- src/Nazara/Utility/X11/InputImpl.hpp | 24 +- src/Nazara/Utility/X11/ScopedXCB.cpp | 327 +- src/Nazara/Utility/X11/ScopedXCB.hpp | 121 +- src/Nazara/Utility/X11/VideoModeImpl.cpp | 281 +- src/Nazara/Utility/X11/VideoModeImpl.hpp | 14 +- src/Nazara/Utility/X11/WindowImpl.cpp | 2955 +++++++++-------- src/Nazara/Utility/X11/WindowImpl.hpp | 183 +- 49 files changed, 3918 insertions(+), 3732 deletions(-) diff --git a/include/Nazara/Prerequesites.hpp b/include/Nazara/Prerequesites.hpp index edc608dff..c2c83626a 100644 --- a/include/Nazara/Prerequesites.hpp +++ b/include/Nazara/Prerequesites.hpp @@ -116,6 +116,7 @@ #endif #elif defined(__linux__) || defined(__unix__) #define NAZARA_PLATFORM_LINUX + #define NAZARA_PLATFORM_GLX #define NAZARA_PLATFORM_POSIX #define NAZARA_PLATFORM_X11 diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index ecac5b526..403a7a534 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -21,10 +21,10 @@ #include #if defined(NAZARA_PLATFORM_WINDOWS) #include -#elif defined(NAZARA_PLATFORM_LINUX) +#elif defined(NAZARA_PLATFORM_GLX) namespace GLX { - #include + #include // Defined in a namespace to avoid conflict } #include #endif @@ -329,7 +329,7 @@ NAZARA_RENDERER_API extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAtt NAZARA_RENDERER_API extern PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB; NAZARA_RENDERER_API extern PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT; NAZARA_RENDERER_API extern PFNWGLSWAPINTERVALEXTPROC wglSwapInterval; -#elif defined(NAZARA_PLATFORM_LINUX) +#elif defined(NAZARA_PLATFORM_GLX) NAZARA_RENDERER_API extern GLX::PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs; NAZARA_RENDERER_API extern GLX::PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT; NAZARA_RENDERER_API extern GLX::PFNGLXSWAPINTERVALMESAPROC NzglXSwapIntervalMESA; diff --git a/include/Nazara/Utility/WindowHandle.hpp b/include/Nazara/Utility/WindowHandle.hpp index 63b5dc2ac..9b5e34c83 100644 --- a/include/Nazara/Utility/WindowHandle.hpp +++ b/include/Nazara/Utility/WindowHandle.hpp @@ -8,14 +8,16 @@ #define NAZARA_WINDOWHANDLE_HPP #include +#if defined(NAZARA_PLATFORM_X11) +#include +#endif namespace Nz { #if defined(NAZARA_PLATFORM_WINDOWS) // http://msdn.microsoft.com/en-us/library/aa383751(v=vs.85).aspx typedef void* WindowHandle; - #elif defined(NAZARA_PLATFORM_LINUX) - #include + #elif defined(NAZARA_PLATFORM_X11) // http://en.wikipedia.org/wiki/Xlib#Data_types using WindowHandle = xcb_window_t; #else diff --git a/src/Nazara/Audio/Debug/NewOverload.cpp b/src/Nazara/Audio/Debug/NewOverload.cpp index ebab9512a..359db9756 100644 --- a/src/Nazara/Audio/Debug/NewOverload.cpp +++ b/src/Nazara/Audio/Debug/NewOverload.cpp @@ -10,22 +10,22 @@ void* operator new(std::size_t size) { - return NzMemoryManager::Allocate(size, false); + return Nz::MemoryManager::Allocate(size, false); } void* operator new[](std::size_t size) { - return NzMemoryManager::Allocate(size, true); + return Nz::MemoryManager::Allocate(size, true); } void operator delete(void* pointer) noexcept { - NzMemoryManager::Free(pointer, false); + Nz::MemoryManager::Free(pointer, false); } void operator delete[](void* pointer) noexcept { - NzMemoryManager::Free(pointer, true); + Nz::MemoryManager::Free(pointer, true); } #endif // NAZARA_AUDIO_MANAGE_MEMORY diff --git a/src/Nazara/Core/Posix/ClockImpl.cpp b/src/Nazara/Core/Posix/ClockImpl.cpp index 9058760b8..73b45b6e7 100644 --- a/src/Nazara/Core/Posix/ClockImpl.cpp +++ b/src/Nazara/Core/Posix/ClockImpl.cpp @@ -8,21 +8,24 @@ #include #include -bool NzClockImplInitializeHighPrecision() +namespace Nz { - return true; // No initialization needed -} + bool ClockImplInitializeHighPrecision() + { + return true; // No initialization needed + } -nzUInt64 NzClockImplGetMicroseconds() -{ - timeval clock; - gettimeofday(&clock, nullptr); - return static_cast(clock.tv_sec*1000000 + clock.tv_usec); -} + UInt64 ClockImplGetElapsedMicroseconds() + { + timeval clock; + gettimeofday(&clock, nullptr); + return static_cast(clock.tv_sec*1000000 + clock.tv_usec); + } -nzUInt64 NzClockImplGetMilliseconds() -{ - timeval clock; - gettimeofday(&clock, nullptr); - return static_cast(clock.tv_sec*1000 + (clock.tv_usec/1000)); + UInt64 ClockImplGetElapsedMilliseconds() + { + timeval clock; + gettimeofday(&clock, nullptr); + return static_cast(clock.tv_sec*1000 + (clock.tv_usec/1000)); + } } diff --git a/src/Nazara/Core/Posix/ClockImpl.hpp b/src/Nazara/Core/Posix/ClockImpl.hpp index 2628214be..552a00bf6 100644 --- a/src/Nazara/Core/Posix/ClockImpl.hpp +++ b/src/Nazara/Core/Posix/ClockImpl.hpp @@ -9,8 +9,11 @@ #include -bool NzClockImplInitializeHighPrecision(); -nzUInt64 NzClockImplGetMicroseconds(); -nzUInt64 NzClockImplGetMilliseconds(); +namespace Nz +{ + bool ClockImplInitializeHighPrecision(); + UInt64 ClockImplGetElapsedMicroseconds(); + UInt64 ClockImplGetElapsedMilliseconds(); +} #endif // NAZARA_CLOCKIMPL_POSIX_HPP diff --git a/src/Nazara/Core/Posix/ConditionVariableImpl.cpp b/src/Nazara/Core/Posix/ConditionVariableImpl.cpp index 7a8ba8fc3..c1c6e891d 100644 --- a/src/Nazara/Core/Posix/ConditionVariableImpl.cpp +++ b/src/Nazara/Core/Posix/ConditionVariableImpl.cpp @@ -6,42 +6,45 @@ #include #include -NzConditionVariableImpl::NzConditionVariableImpl() +namespace Nz { - pthread_cond_init(&m_cv, nullptr); -} - -NzConditionVariableImpl::~NzConditionVariableImpl() -{ - pthread_cond_destroy(&m_cv); -} - -void NzConditionVariableImpl::Signal() -{ - pthread_cond_signal(&m_cv); -} - -void NzConditionVariableImpl::SignalAll() -{ - pthread_cond_broadcast(&m_cv); -} - -void NzConditionVariableImpl::Wait(NzMutexImpl* mutex) -{ - pthread_cond_wait(&m_cv, &mutex->m_handle); -} - -bool NzConditionVariableImpl::Wait(NzMutexImpl* mutex, nzUInt32 timeout) -{ - // get the current time - timeval tv; - gettimeofday(&tv, nullptr); - - // construct the time limit (current time + time to wait) - timespec ti; - ti.tv_nsec = (tv.tv_usec + (timeout % 1000)) * 1000000; - ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000); - ti.tv_nsec %= 1000000000; - - return pthread_cond_timedwait(&m_cv,&mutex->m_handle, &ti) != 0; + ConditionVariableImpl::ConditionVariableImpl() + { + pthread_cond_init(&m_cv, nullptr); + } + + ConditionVariableImpl::~ConditionVariableImpl() + { + pthread_cond_destroy(&m_cv); + } + + void ConditionVariableImpl::Signal() + { + pthread_cond_signal(&m_cv); + } + + void ConditionVariableImpl::SignalAll() + { + pthread_cond_broadcast(&m_cv); + } + + void ConditionVariableImpl::Wait(MutexImpl* mutex) + { + pthread_cond_wait(&m_cv, &mutex->m_handle); + } + + bool ConditionVariableImpl::Wait(MutexImpl* mutex, UInt32 timeout) + { + // get the current time + timeval tv; + gettimeofday(&tv, nullptr); + + // construct the time limit (current time + time to wait) + timespec ti; + ti.tv_nsec = (tv.tv_usec + (timeout % 1000)) * 1000000; + ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000); + ti.tv_nsec %= 1000000000; + + return pthread_cond_timedwait(&m_cv,&mutex->m_handle, &ti) != 0; + } } diff --git a/src/Nazara/Core/Posix/ConditionVariableImpl.hpp b/src/Nazara/Core/Posix/ConditionVariableImpl.hpp index a49cbf901..1781711c4 100644 --- a/src/Nazara/Core/Posix/ConditionVariableImpl.hpp +++ b/src/Nazara/Core/Posix/ConditionVariableImpl.hpp @@ -14,22 +14,25 @@ #include #include -class NzMutexImpl; - -class NzConditionVariableImpl +namespace Nz { - public: - NzConditionVariableImpl(); - ~NzConditionVariableImpl(); + class MutexImpl; - void Signal(); - void SignalAll(); + class ConditionVariableImpl + { + public: + ConditionVariableImpl(); + ~ConditionVariableImpl(); - void Wait(NzMutexImpl* mutex); - bool Wait(NzMutexImpl* mutex, nzUInt32 timeout); + void Signal(); + void SignalAll(); - private: - pthread_cond_t m_cv; -}; + void Wait(MutexImpl* mutex); + bool Wait(MutexImpl* mutex, UInt32 timeout); + + private: + pthread_cond_t m_cv; + }; +} #endif // NAZARA_CONDITIONVARIABLEIMPL_HPP diff --git a/src/Nazara/Core/Posix/DirectoryImpl.cpp b/src/Nazara/Core/Posix/DirectoryImpl.cpp index 76155e12c..4abf575b3 100644 --- a/src/Nazara/Core/Posix/DirectoryImpl.cpp +++ b/src/Nazara/Core/Posix/DirectoryImpl.cpp @@ -9,95 +9,98 @@ #include #include -NzDirectoryImpl::NzDirectoryImpl(const NzDirectory* parent) +namespace Nz { - NazaraUnused(parent); -} + DirectoryImpl::DirectoryImpl(const Directory* parent) + { + NazaraUnused(parent); + } -void NzDirectoryImpl::Close() -{ - closedir(m_handle); -} + void DirectoryImpl::Close() + { + closedir(m_handle); + } -NzString NzDirectoryImpl::GetResultName() const -{ - return m_result->d_name; -} + String DirectoryImpl::GetResultName() const + { + return m_result->d_name; + } -nzUInt64 NzDirectoryImpl::GetResultSize() const -{ - struct stat64 resulststat; - stat64(m_result->d_name, &resulststat); + UInt64 DirectoryImpl::GetResultSize() const + { + struct stat64 resulststat; + stat64(m_result->d_name, &resulststat); - return static_cast(resulststat.st_size); -} + return static_cast(resulststat.st_size); + } -bool NzDirectoryImpl::IsResultDirectory() const -{ - struct stat64 filestats; - if (stat64(m_result->d_name, &filestats) == -1) // error - return false; + bool DirectoryImpl::IsResultDirectory() const + { + struct stat64 filestats; + if (stat64(m_result->d_name, &filestats) == -1) // error + return false; - return S_ISDIR(filestats.st_mode); -} + return S_ISDIR(filestats.st_mode); + } + + bool DirectoryImpl::NextResult() + { + if ((m_result = readdir64(m_handle))) + return true; + else + { + if (errno != ENOENT) + NazaraError("Unable to get next result: " + Error::GetLastSystemError()); + + return false; + } + } + + bool DirectoryImpl::Open(const String& dirPath) + { + m_handle = opendir(dirPath.GetConstBuffer()); + if (!m_handle) + { + NazaraError("Unable to open directory: " + Error::GetLastSystemError()); + return false; + } -bool NzDirectoryImpl::NextResult() -{ - if ((m_result = readdir64(m_handle))) return true; - else - { - if (errno != ENOENT) - NazaraError("Unable to get next result: " + NzError::GetLastSystemError()); - - return false; - } -} - -bool NzDirectoryImpl::Open(const NzString& dirPath) -{ - m_handle = opendir(dirPath.GetConstBuffer()); - if (!m_handle) - { - NazaraError("Unable to open directory: " + NzError::GetLastSystemError()); - return false; } - return true; -} - -bool NzDirectoryImpl::Create(const NzString& dirPath) -{ - mode_t permissions; // TODO: check permissions - - return mkdir(dirPath.GetConstBuffer(), permissions) != -1;; -} - -bool NzDirectoryImpl::Exists(const NzString& dirPath) -{ - struct stat64 filestats; - if (stat64(dirPath.GetConstBuffer(), &filestats) == -1) // error - return false; - - return S_ISDIR(filestats.st_mode) || S_ISREG(filestats.st_mode); -} - -NzString NzDirectoryImpl::GetCurrent() -{ - NzString currentPath; - - char path[MAXPATHLEN]; - if (getcwd(path, MAXPATHLEN)) - currentPath = path; - else - NazaraError("Unable to get current directory: " + NzError::GetLastSystemError()); // Bug: initialisation -> if no path for log ! - - return currentPath; -} - -bool NzDirectoryImpl::Remove(const NzString& dirPath) -{ - bool success = rmdir(dirPath.GetConstBuffer()) != -1; - - return success; + bool DirectoryImpl::Create(const String& dirPath) + { + mode_t permissions; // TODO: check permissions + + return mkdir(dirPath.GetConstBuffer(), permissions) != -1;; + } + + bool DirectoryImpl::Exists(const String& dirPath) + { + struct stat64 filestats; + if (stat64(dirPath.GetConstBuffer(), &filestats) == -1) // error + return false; + + return S_ISDIR(filestats.st_mode) || S_ISREG(filestats.st_mode); + } + + String DirectoryImpl::GetCurrent() + { + String currentPath; + + char path[MAXPATHLEN]; + if (getcwd(path, MAXPATHLEN)) + currentPath = path; + else + NazaraError("Unable to get current directory: " + Error::GetLastSystemError()); // Bug: initialisation -> if no path for log ! + + return currentPath; + } + + bool DirectoryImpl::Remove(const String& dirPath) + { + bool success = rmdir(dirPath.GetConstBuffer()) != -1; + + return success; + } } diff --git a/src/Nazara/Core/Posix/DirectoryImpl.hpp b/src/Nazara/Core/Posix/DirectoryImpl.hpp index 858e21930..5f77fbb43 100644 --- a/src/Nazara/Core/Posix/DirectoryImpl.hpp +++ b/src/Nazara/Core/Posix/DirectoryImpl.hpp @@ -8,40 +8,47 @@ #define NAZARA_DIRECTORYIMPL_HPP #include -#include #include #include #include #include -class NzDirectory; -class NzString; - -class NzDirectoryImpl : NzNonCopyable +namespace Nz { - public: - NzDirectoryImpl(const NzDirectory* parent); - ~NzDirectoryImpl() = default; + class Directory; + class String; - void Close(); + class DirectoryImpl + { + public: + DirectoryImpl(const Directory* parent); + DirectoryImpl(const DirectoryImpl&) = delete; + DirectoryImpl(DirectoryImpl&&) = delete; ///TODO + ~DirectoryImpl() = default; - NzString GetResultName() const; - nzUInt64 GetResultSize() const; + void Close(); - bool IsResultDirectory() const; + String GetResultName() const; + UInt64 GetResultSize() const; - bool NextResult(); + bool IsResultDirectory() const; - bool Open(const NzString& dirPath); + bool NextResult(); - static bool Create(const NzString& dirPath); - static bool Exists(const NzString& dirPath); - static NzString GetCurrent(); - static bool Remove(const NzString& dirPath); + bool Open(const String& dirPath); - private: - DIR* m_handle; - dirent64* m_result; -}; + DirectoryImpl& operator=(const DirectoryImpl&) = delete; + DirectoryImpl& operator=(DirectoryImpl&&) = delete; ///TODO + + static bool Create(const String& dirPath); + static bool Exists(const String& dirPath); + static String GetCurrent(); + static bool Remove(const String& dirPath); + + private: + DIR* m_handle; + dirent64* m_result; + }; +} #endif // NAZARA_DIRECTORYIMPL_HPP diff --git a/src/Nazara/Core/Posix/DynLibImpl.cpp b/src/Nazara/Core/Posix/DynLibImpl.cpp index b3bafebda..dbb8463fa 100644 --- a/src/Nazara/Core/Posix/DynLibImpl.cpp +++ b/src/Nazara/Core/Posix/DynLibImpl.cpp @@ -8,55 +8,58 @@ #include #include -NzDynLibImpl::NzDynLibImpl(NzDynLib* parent) +namespace Nz { - NazaraUnused(parent); -} - -NzDynLibFunc NzDynLibImpl::GetSymbol(const NzString& symbol, NzString* errorMessage) const -{ - /* - Il n'est pas standard de cast un pointeur d'objet vers un pointeur de fonction. - Nous devons donc utiliser des techniques diaboliques venant du malin lui-même.. :D - Au moins ce n'est pas aussi terrible qu'un const_cast - -Lynix - */ - union + DynLibImpl::DynLibImpl(DynLib* parent) { - NzDynLibFunc func; - void* pointer; - } converter; + NazaraUnused(parent); + } - dlerror(); // Clear error flag - - converter.pointer = dlsym(m_handle, symbol.GetConstBuffer()); - if (!converter.pointer) - *errorMessage = dlerror(); - - return converter.func; -} - -bool NzDynLibImpl::Load(const NzString& libraryPath, NzString* errorMessage) -{ - NzString path = libraryPath; - - unsigned int pos = path.FindLast(".so"); - if (pos == NzString::npos || (path.GetLength() > pos+3 && path[pos+3] != '.')) - path += ".so"; - - dlerror(); // Clear error flag - m_handle = dlopen(path.GetConstBuffer(), RTLD_LAZY | RTLD_GLOBAL); - - if (m_handle) - return true; - else + DynLibFunc DynLibImpl::GetSymbol(const String& symbol, String* errorMessage) const { - *errorMessage = dlerror(); - return false; + /* + Il n'est pas standard de cast un pointeur d'objet vers un pointeur de fonction. + Nous devons donc utiliser des techniques diaboliques venant du malin lui-même.. :D + Au moins ce n'est pas aussi terrible qu'un const_cast + -Lynix + */ + union + { + DynLibFunc func; + void* pointer; + } converter; + + dlerror(); // Clear error flag + + converter.pointer = dlsym(m_handle, symbol.GetConstBuffer()); + if (!converter.pointer) + *errorMessage = dlerror(); + + return converter.func; + } + + bool DynLibImpl::Load(const String& libraryPath, String* errorMessage) + { + String path = libraryPath; + + unsigned int pos = path.FindLast(".so"); + if (pos == String::npos || (path.GetLength() > pos+3 && path[pos+3] != '.')) + path += ".so"; + + dlerror(); // Clear error flag + m_handle = dlopen(path.GetConstBuffer(), RTLD_LAZY | RTLD_GLOBAL); + + if (m_handle) + return true; + else + { + *errorMessage = dlerror(); + return false; + } + } + + void DynLibImpl::Unload() + { + dlclose(m_handle); } } - -void NzDynLibImpl::Unload() -{ - dlclose(m_handle); -} diff --git a/src/Nazara/Core/Posix/DynLibImpl.hpp b/src/Nazara/Core/Posix/DynLibImpl.hpp index 5e4cac8d5..1f36fa9e3 100644 --- a/src/Nazara/Core/Posix/DynLibImpl.hpp +++ b/src/Nazara/Core/Posix/DynLibImpl.hpp @@ -8,23 +8,25 @@ #define NAZARA_DYNLIBIMPL_HPP #include -#include #include -class NzString; - -class NzDynLibImpl : NzNonCopyable +namespace Nz { - public: - NzDynLibImpl(NzDynLib* m_parent); - ~NzDynLibImpl() = default; + class String; - NzDynLibFunc GetSymbol(const NzString& symbol, NzString* errorMessage) const; - bool Load(const NzString& libraryPath, NzString* errorMessage); - void Unload(); + class DynLibImpl + { + public: + DynLibImpl(DynLib* m_parent); + ~DynLibImpl() = default; - private: - void* m_handle; -}; + DynLibFunc GetSymbol(const String& symbol, String* errorMessage) const; + bool Load(const String& libraryPath, String* errorMessage); + void Unload(); + + private: + void* m_handle; + }; +} #endif // NAZARA_DYNLIBIMPL_HPP diff --git a/src/Nazara/Core/Posix/FileImpl.cpp b/src/Nazara/Core/Posix/FileImpl.cpp index b33dce80b..9c1469817 100644 --- a/src/Nazara/Core/Posix/FileImpl.cpp +++ b/src/Nazara/Core/Posix/FileImpl.cpp @@ -7,236 +7,239 @@ #include #include -NzFileImpl::NzFileImpl(const NzFile* parent) : -m_endOfFile(false), -m_endOfFileUpdated(true) +namespace Nz { - NazaraUnused(parent); -} - -void NzFileImpl::Close() -{ - close(m_fileDescriptor); -} - -bool NzFileImpl::EndOfFile() const -{ - if (!m_endOfFileUpdated) + FileImpl::FileImpl(const File* parent) : + m_endOfFile(false), + m_endOfFileUpdated(true) { - struct stat64 fileSize; - if (fstat64(m_fileDescriptor, &fileSize) == -1) - fileSize.st_size = 0; - - m_endOfFile = (GetCursorPos() >= static_cast(fileSize.st_size)); - m_endOfFileUpdated = true; + NazaraUnused(parent); } - return m_endOfFile; -} - -void NzFileImpl::Flush() -{ - if (fsync(m_fileDescriptor) == -1) - NazaraError("Unable to flush file: " + NzError::GetLastSystemError()); -} - -nzUInt64 NzFileImpl::GetCursorPos() const -{ - off64_t position = lseek64(m_fileDescriptor, 0, SEEK_CUR); - return static_cast(position); -} - -bool NzFileImpl::Open(const NzString& filePath, unsigned int mode) -{ - int flags; - mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - - if (mode & nzOpenMode_ReadOnly) - flags = O_RDONLY; - else if (mode & nzOpenMode_ReadWrite) + void FileImpl::Close() { - flags = O_CREAT | O_RDWR; - - if (mode & nzOpenMode_Append) - flags |= O_APPEND; - - if (mode & nzOpenMode_Truncate) - flags |= O_TRUNC; - } - else if (mode & nzOpenMode_WriteOnly) - { - flags = O_CREAT | O_WRONLY; - - if (mode & nzOpenMode_Append) - flags |= O_APPEND; - - if (mode & nzOpenMode_Truncate) - flags |= O_TRUNC; - } - else - return false; - -///TODO: lock -// if ((mode & nzOpenMode_Lock) == 0) -// shareMode |= FILE_SHARE_WRITE; - - m_fileDescriptor = open64(filePath.GetConstBuffer(), flags, permissions); - return m_fileDescriptor != -1; -} - -std::size_t NzFileImpl::Read(void* buffer, std::size_t size) -{ - ssize_t bytes; - if ((bytes = read(m_fileDescriptor, buffer, size)) != -1) - { - m_endOfFile = (static_cast(bytes) != size); - m_endOfFileUpdated = true; - - return static_cast(bytes); - } - else - return 0; -} - -bool NzFileImpl::SetCursorPos(nzCursorPosition pos, nzInt64 offset) -{ - int moveMethod; - switch (pos) - { - case nzCursorPosition_AtBegin: - moveMethod = SEEK_SET; - break; - - case nzCursorPosition_AtCurrent: - moveMethod = SEEK_CUR; - break; - - case nzCursorPosition_AtEnd: - moveMethod = SEEK_END; - break; - - default: - NazaraInternalError("Cursor position not handled (0x" + NzString::Number(pos, 16) + ')'); - return false; + close(m_fileDescriptor); } - m_endOfFileUpdated = false; - - return lseek64(m_fileDescriptor, offset, moveMethod) != -1; -} - -std::size_t NzFileImpl::Write(const void* buffer, std::size_t size) -{ - lockf64(m_fileDescriptor, F_LOCK, size); - ssize_t written = write(m_fileDescriptor, buffer, size); - lockf64(m_fileDescriptor, F_ULOCK, size); - - m_endOfFileUpdated = false; - - return written; -} - -bool NzFileImpl::Copy(const NzString& sourcePath, const NzString& targetPath) -{ - int fd1 = open64(sourcePath.GetConstBuffer(), O_RDONLY); - if (fd1 == -1) + bool FileImpl::EndOfFile() const { - NazaraError("Fail to open input file (" + sourcePath + "): " + NzError::GetLastSystemError()); - return false; - } - - mode_t permissions; // TODO : get permission from first file - int fd2 = open64(targetPath.GetConstBuffer(), O_WRONLY | O_TRUNC, permissions); - if (fd2 == -1) - { - NazaraError("Fail to open output file (" + targetPath + "): " + NzError::GetLastSystemError()); // TODO: more info ? - close(fd1); - return false; - } - - char buffer[512]; - ssize_t bytes; - do - { - bytes = read(fd1,buffer,512); - if (bytes == -1) + if (!m_endOfFileUpdated) { - close(fd1); - close(fd2); - NazaraError("An error occured from copy : " + NzError::GetLastSystemError()); + struct stat64 fileSize; + if (fstat64(m_fileDescriptor, &fileSize) == -1) + fileSize.st_size = 0; + + m_endOfFile = (GetCursorPos() >= static_cast(fileSize.st_size)); + m_endOfFileUpdated = true; + } + + return m_endOfFile; + } + + void FileImpl::Flush() + { + if (fsync(m_fileDescriptor) == -1) + NazaraError("Unable to flush file: " + Error::GetLastSystemError()); + } + + UInt64 FileImpl::GetCursorPos() const + { + off64_t position = lseek64(m_fileDescriptor, 0, SEEK_CUR); + return static_cast(position); + } + + bool FileImpl::Open(const String& filePath, unsigned int mode) + { + int flags; + mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + + if (mode & OpenMode_ReadOnly) + flags = O_RDONLY; + else if (mode & OpenMode_ReadWrite) + { + flags = O_CREAT | O_RDWR; + + if (mode & OpenMode_Append) + flags |= O_APPEND; + + if (mode & OpenMode_Truncate) + flags |= O_TRUNC; + } + else if (mode & OpenMode_WriteOnly) + { + flags = O_CREAT | O_WRONLY; + + if (mode & OpenMode_Append) + flags |= O_APPEND; + + if (mode & OpenMode_Truncate) + flags |= O_TRUNC; + } + else + return false; + + ///TODO: lock + // if ((mode & OpenMode_Lock) == 0) + // shareMode |= FILE_SHARE_WRITE; + + m_fileDescriptor = open64(filePath.GetConstBuffer(), flags, permissions); + return m_fileDescriptor != -1; + } + + std::size_t FileImpl::Read(void* buffer, std::size_t size) + { + ssize_t bytes; + if ((bytes = read(m_fileDescriptor, buffer, size)) != -1) + { + m_endOfFile = (static_cast(bytes) != size); + m_endOfFileUpdated = true; + + return static_cast(bytes); + } + else + return 0; + } + + bool FileImpl::SetCursorPos(CursorPosition pos, Int64 offset) + { + int moveMethod; + switch (pos) + { + case CursorPosition_AtBegin: + moveMethod = SEEK_SET; + break; + + case CursorPosition_AtCurrent: + moveMethod = SEEK_CUR; + break; + + case CursorPosition_AtEnd: + moveMethod = SEEK_END; + break; + + default: + NazaraInternalError("Cursor position not handled (0x" + String::Number(pos, 16) + ')'); + return false; + } + + m_endOfFileUpdated = false; + + return lseek64(m_fileDescriptor, offset, moveMethod) != -1; + } + + std::size_t FileImpl::Write(const void* buffer, std::size_t size) + { + lockf64(m_fileDescriptor, F_LOCK, size); + ssize_t written = write(m_fileDescriptor, buffer, size); + lockf64(m_fileDescriptor, F_ULOCK, size); + + m_endOfFileUpdated = false; + + return written; + } + + bool FileImpl::Copy(const String& sourcePath, const String& targetPath) + { + int fd1 = open64(sourcePath.GetConstBuffer(), O_RDONLY); + if (fd1 == -1) + { + NazaraError("Fail to open input file (" + sourcePath + "): " + Error::GetLastSystemError()); return false; } - write(fd2,buffer,bytes); - } - while (bytes == 512); - close(fd1); - close(fd2); - return true; -} + mode_t permissions; // TODO : get permission from first file + int fd2 = open64(targetPath.GetConstBuffer(), O_WRONLY | O_TRUNC, permissions); + if (fd2 == -1) + { + NazaraError("Fail to open output file (" + targetPath + "): " + Error::GetLastSystemError()); // TODO: more info ? + close(fd1); + return false; + } -bool NzFileImpl::Delete(const NzString& filePath) -{ - bool success = unlink(filePath.GetConstBuffer()) != -1; + char buffer[512]; + ssize_t bytes; + do + { + bytes = read(fd1,buffer,512); + if (bytes == -1) + { + close(fd1); + close(fd2); + NazaraError("An error occured from copy : " + Error::GetLastSystemError()); + return false; + } + write(fd2,buffer,bytes); + } + while (bytes == 512); - if (success) + close(fd1); + close(fd2); return true; - else + } + + bool FileImpl::Delete(const String& filePath) { - NazaraError("Failed to delete file (" + filePath + "): " + NzError::GetLastSystemError()); + bool success = unlink(filePath.GetConstBuffer()) != -1; + + if (success) + return true; + else + { + NazaraError("Failed to delete file (" + filePath + "): " + Error::GetLastSystemError()); + return false; + } + } + + bool FileImpl::Exists(const String& filePath) + { + const char* path = filePath.GetConstBuffer(); + if (access(path, F_OK) != -1) + return true; + return false; } -} -bool NzFileImpl::Exists(const NzString& filePath) -{ - const char* path = filePath.GetConstBuffer(); - if (access(path, F_OK) != -1) - return true; - - return false; -} - -time_t NzFileImpl::GetCreationTime(const NzString& filePath) -{ - NazaraWarning("Posix has no creation time information"); - - return 0; -} - -time_t NzFileImpl::GetLastAccessTime(const NzString& filePath) -{ - struct stat64 stats; - stat64(filePath.GetConstBuffer(), &stats); - - return stats.st_atime; -} - -time_t NzFileImpl::GetLastWriteTime(const NzString& filePath) -{ - struct stat64 stats; - stat64(filePath.GetConstBuffer(), &stats); - - return stats.st_mtime; -} - -nzUInt64 NzFileImpl::GetSize(const NzString& filePath) -{ - struct stat64 stats; - stat64(filePath.GetConstBuffer(), &stats); - - return static_cast(stats.st_size); -} - -bool NzFileImpl::Rename(const NzString& sourcePath, const NzString& targetPath) -{ - bool success = std::rename(sourcePath.GetConstBuffer(), targetPath.GetConstBuffer()) != -1; - - if (success) - return true; - else + time_t FileImpl::GetCreationTime(const String& filePath) { - NazaraError("Unable to rename file: " + NzError::GetLastSystemError()); - return false; + NazaraWarning("Posix has no creation time information"); + + return 0; + } + + time_t FileImpl::GetLastAccessTime(const String& filePath) + { + struct stat64 stats; + stat64(filePath.GetConstBuffer(), &stats); + + return stats.st_atime; + } + + time_t FileImpl::GetLastWriteTime(const String& filePath) + { + struct stat64 stats; + stat64(filePath.GetConstBuffer(), &stats); + + return stats.st_mtime; + } + + UInt64 FileImpl::GetSize(const String& filePath) + { + struct stat64 stats; + stat64(filePath.GetConstBuffer(), &stats); + + return static_cast(stats.st_size); + } + + bool FileImpl::Rename(const String& sourcePath, const String& targetPath) + { + bool success = std::rename(sourcePath.GetConstBuffer(), targetPath.GetConstBuffer()) != -1; + + if (success) + return true; + else + { + NazaraError("Unable to rename file: " + Error::GetLastSystemError()); + return false; + } } } diff --git a/src/Nazara/Core/Posix/FileImpl.hpp b/src/Nazara/Core/Posix/FileImpl.hpp index eda3f5400..6531dc70b 100644 --- a/src/Nazara/Core/Posix/FileImpl.hpp +++ b/src/Nazara/Core/Posix/FileImpl.hpp @@ -13,44 +13,51 @@ #include #include -#include #include #include #include #include #include -class NzFile; -class NzString; - -class NzFileImpl : NzNonCopyable +namespace Nz { - public: - NzFileImpl(const NzFile* parent); - ~NzFileImpl() = default; + class File; + class String; - void Close(); - bool EndOfFile() const; - void Flush(); - nzUInt64 GetCursorPos() const; - bool Open(const NzString& filePath, unsigned int mode); - std::size_t Read(void* buffer, std::size_t size); - bool SetCursorPos(nzCursorPosition pos, nzInt64 offset); - std::size_t Write(const void* buffer, std::size_t size); + class FileImpl + { + public: + FileImpl(const File* parent); + FileImpl(const FileImpl&) = delete; + FileImpl(FileImpl&&) = delete; ///TODO + ~FileImpl() = default; - static bool Copy(const NzString& sourcePath, const NzString& targetPath); - static bool Delete(const NzString& filePath); - static bool Exists(const NzString& filePath); - static time_t GetCreationTime(const NzString& filePath); - static time_t GetLastAccessTime(const NzString& filePath); - static time_t GetLastWriteTime(const NzString& filePath); - static nzUInt64 GetSize(const NzString& filePath); - static bool Rename(const NzString& sourcePath, const NzString& targetPath); + void Close(); + bool EndOfFile() const; + void Flush(); + UInt64 GetCursorPos() const; + bool Open(const String& filePath, unsigned int mode); + std::size_t Read(void* buffer, std::size_t size); + bool SetCursorPos(CursorPosition pos, Int64 offset); + std::size_t Write(const void* buffer, std::size_t size); - private: - int m_fileDescriptor; - mutable bool m_endOfFile; - mutable bool m_endOfFileUpdated; -}; + FileImpl& operator=(const FileImpl&) = delete; + FileImpl& operator=(FileImpl&&) = delete; ///TODO + + static bool Copy(const String& sourcePath, const String& targetPath); + static bool Delete(const String& filePath); + static bool Exists(const String& filePath); + static time_t GetCreationTime(const String& filePath); + static time_t GetLastAccessTime(const String& filePath); + static time_t GetLastWriteTime(const String& filePath); + static UInt64 GetSize(const String& filePath); + static bool Rename(const String& sourcePath, const String& targetPath); + + private: + int m_fileDescriptor; + mutable bool m_endOfFile; + mutable bool m_endOfFileUpdated; + }; +} #endif // NAZARA_FILEIMPL_HPP diff --git a/src/Nazara/Core/Posix/HardwareInfoImpl.cpp b/src/Nazara/Core/Posix/HardwareInfoImpl.cpp index 31713defd..0058832a8 100644 --- a/src/Nazara/Core/Posix/HardwareInfoImpl.cpp +++ b/src/Nazara/Core/Posix/HardwareInfoImpl.cpp @@ -6,58 +6,61 @@ #include #include -void NzHardwareInfoImpl::Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4]) +namespace Nz { -#if defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL) - // Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c - asm volatile ("cpuid" // Besoin d'être volatile ? - : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output - : "a" (functionId), "c" (subFunctionId)); // input -#else - NazaraInternalError("Cpuid has been called although it is not supported"); -#endif -} - -unsigned int NzHardwareInfoImpl::GetProcessorCount() -{ - // Plus simple (et plus portable) que de passer par le CPUID - return sysconf(_SC_NPROCESSORS_CONF); -} - -nzUInt64 NzHardwareInfoImpl::GetTotalMemory() -{ - nzUInt64 pages = sysconf(_SC_PHYS_PAGES); - nzUInt64 page_size = sysconf(_SC_PAGE_SIZE); - - return pages * page_size; -} - -bool NzHardwareInfoImpl::IsCpuidSupported() -{ -#ifdef NAZARA_PLATFORM_x64 - return true; // Toujours supporté sur un processeur 64 bits -#else + void HardwareInfoImpl::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4]) + { #if defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL) - int supported; - asm volatile (" pushfl\n" - " pop %%eax\n" - " mov %%eax, %%ecx\n" - " xor $0x200000, %%eax\n" - " push %%eax\n" - " popfl\n" - " pushfl\n" - " pop %%eax\n" - " xor %%ecx, %%eax\n" - " mov %%eax, %0\n" - " push %%ecx\n" - " popfl" - : "=m" (supported) // output - : // input - : "eax", "ecx", "memory"); // clobbered register - - return supported != 0; + // Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c + asm volatile ("cpuid" // Besoin d'être volatile ? + : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output + : "a" (functionId), "c" (subFunctionId)); // input #else - return false; + NazaraInternalError("Cpuid has been called although it is not supported"); #endif -#endif + } + + unsigned int HardwareInfoImpl::GetProcessorCount() + { + // Plus simple (et plus portable) que de passer par le CPUID + return sysconf(_SC_NPROCESSORS_CONF); + } + + UInt64 HardwareInfoImpl::GetTotalMemory() + { + UInt64 pages = sysconf(_SC_PHYS_PAGES); + UInt64 page_size = sysconf(_SC_PAGE_SIZE); + + return pages * page_size; + } + + bool HardwareInfoImpl::IsCpuidSupported() + { + #ifdef NAZARA_PLATFORM_x64 + return true; // Toujours supporté sur un processeur 64 bits + #else + #if defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL) + int supported; + asm volatile (" pushfl\n" + " pop %%eax\n" + " mov %%eax, %%ecx\n" + " xor $0x200000, %%eax\n" + " push %%eax\n" + " popfl\n" + " pushfl\n" + " pop %%eax\n" + " xor %%ecx, %%eax\n" + " mov %%eax, %0\n" + " push %%ecx\n" + " popfl" + : "=m" (supported) // output + : // input + : "eax", "ecx", "memory"); // clobbered register + + return supported != 0; + #else + return false; + #endif + #endif + } } diff --git a/src/Nazara/Core/Posix/HardwareInfoImpl.hpp b/src/Nazara/Core/Posix/HardwareInfoImpl.hpp index ef05a7aeb..671802c52 100644 --- a/src/Nazara/Core/Posix/HardwareInfoImpl.hpp +++ b/src/Nazara/Core/Posix/HardwareInfoImpl.hpp @@ -10,13 +10,16 @@ #include #include -class NzHardwareInfoImpl +namespace Nz { - public: - static void Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4]); - static unsigned int GetProcessorCount(); - static nzUInt64 GetTotalMemory(); - static bool IsCpuidSupported(); -}; + class HardwareInfoImpl + { + public: + static void Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4]); + static unsigned int GetProcessorCount(); + static UInt64 GetTotalMemory(); + static bool IsCpuidSupported(); + }; +} #endif // NAZARA_HARDWAREINFOIMPL_POSIX_HPP diff --git a/src/Nazara/Core/Posix/MutexImpl.cpp b/src/Nazara/Core/Posix/MutexImpl.cpp index c53ad61ff..a19720000 100644 --- a/src/Nazara/Core/Posix/MutexImpl.cpp +++ b/src/Nazara/Core/Posix/MutexImpl.cpp @@ -5,31 +5,34 @@ #include #include -NzMutexImpl::NzMutexImpl() +namespace Nz { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + MutexImpl::MutexImpl() + { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m_handle, &attr); -} + pthread_mutex_init(&m_handle, &attr); + } -NzMutexImpl::~NzMutexImpl() -{ - pthread_mutex_destroy(&m_handle); -} + MutexImpl::~MutexImpl() + { + pthread_mutex_destroy(&m_handle); + } -void NzMutexImpl::Lock() -{ - pthread_mutex_lock(&m_handle); -} + void MutexImpl::Lock() + { + pthread_mutex_lock(&m_handle); + } -bool NzMutexImpl::TryLock() -{ - return pthread_mutex_trylock(&m_handle) == 0; -} + bool MutexImpl::TryLock() + { + return pthread_mutex_trylock(&m_handle) == 0; + } -void NzMutexImpl::Unlock() -{ - pthread_mutex_unlock(&m_handle); + void MutexImpl::Unlock() + { + pthread_mutex_unlock(&m_handle); + } } diff --git a/src/Nazara/Core/Posix/MutexImpl.hpp b/src/Nazara/Core/Posix/MutexImpl.hpp index ff1d0455f..5437ce043 100644 --- a/src/Nazara/Core/Posix/MutexImpl.hpp +++ b/src/Nazara/Core/Posix/MutexImpl.hpp @@ -9,20 +9,23 @@ #include -class NzMutexImpl +namespace Nz { - friend class NzConditionVariableImpl; + class MutexImpl + { + friend class ConditionVariableImpl; - public: - NzMutexImpl(); - ~NzMutexImpl(); + public: + MutexImpl(); + ~MutexImpl(); - void Lock(); - bool TryLock(); - void Unlock(); + void Lock(); + bool TryLock(); + void Unlock(); - private: - pthread_mutex_t m_handle; -}; + private: + pthread_mutex_t m_handle; + }; +} #endif // NAZARA_MUTEXIMPL_HPP diff --git a/src/Nazara/Core/Posix/SemaphoreImpl.cpp b/src/Nazara/Core/Posix/SemaphoreImpl.cpp index baa70f10a..4342cf1c6 100644 --- a/src/Nazara/Core/Posix/SemaphoreImpl.cpp +++ b/src/Nazara/Core/Posix/SemaphoreImpl.cpp @@ -9,63 +9,66 @@ #include #include -NzSemaphoreImpl::NzSemaphoreImpl(unsigned int count) +namespace Nz { - if(sem_init(&m_semaphore, 0, count) != 0) - NazaraError("Failed to create semaphore: " + NzError::GetLastSystemError()); -} - -NzSemaphoreImpl::~NzSemaphoreImpl() -{ - sem_destroy(&m_semaphore); -} - -unsigned int NzSemaphoreImpl::GetCount() const -{ - int count=0; - sem_getvalue(const_cast(&m_semaphore), &count); - return static_cast(count); -} - -void NzSemaphoreImpl::Post() -{ - #if NAZARA_CORE_SAFE - if (sem_post(&m_semaphore)==-1) - NazaraError("Failed to release semaphore: " + NzError::GetLastSystemError()); - #else - sem_post(&m_semaphore); - #endif -} - -void NzSemaphoreImpl::Wait() -{ - #if NAZARA_CORE_SAFE - if (sem_wait(&m_semaphore) == -1 ) - NazaraError("Failed to wait for semaphore: " + NzError::GetLastSystemError()); - #else - sem_wait(&m_semaphore); - #endif -} - -bool NzSemaphoreImpl::Wait(nzUInt32 timeout) -{ - timeval tv; - gettimeofday(&tv, nullptr); - - timespec ti; - ti.tv_nsec = (tv.tv_usec + (timeout % 1000)) * 1000000; - ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000); - ti.tv_nsec %= 1000000000; - - #if NAZARA_CORE_SAFE - if (sem_timedwait(&m_semaphore, &ti) != 0) + SemaphoreImpl::SemaphoreImpl(unsigned int count) { - NazaraError("Failed to wait for semaphore: " + NzError::GetLastSystemError()); - return false; + if(sem_init(&m_semaphore, 0, count) != 0) + NazaraError("Failed to create semaphore: " + Error::GetLastSystemError()); } - return true; - #else - return sem_timedwait(&m_semaphore, &ti) != 0; - #endif + SemaphoreImpl::~SemaphoreImpl() + { + sem_destroy(&m_semaphore); + } + + unsigned int SemaphoreImpl::GetCount() const + { + int count=0; + sem_getvalue(const_cast(&m_semaphore), &count); + return static_cast(count); + } + + void SemaphoreImpl::Post() + { + #if NAZARA_CORE_SAFE + if (sem_post(&m_semaphore)==-1) + NazaraError("Failed to release semaphore: " + Error::GetLastSystemError()); + #else + sem_post(&m_semaphore); + #endif + } + + void SemaphoreImpl::Wait() + { + #if NAZARA_CORE_SAFE + if (sem_wait(&m_semaphore) == -1 ) + NazaraError("Failed to wait for semaphore: " + Error::GetLastSystemError()); + #else + sem_wait(&m_semaphore); + #endif + } + + bool SemaphoreImpl::Wait(UInt32 timeout) + { + timeval tv; + gettimeofday(&tv, nullptr); + + timespec ti; + ti.tv_nsec = (tv.tv_usec + (timeout % 1000)) * 1000000; + ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000); + ti.tv_nsec %= 1000000000; + + #if NAZARA_CORE_SAFE + if (sem_timedwait(&m_semaphore, &ti) != 0) + { + NazaraError("Failed to wait for semaphore: " + Error::GetLastSystemError()); + return false; + } + + return true; + #else + return sem_timedwait(&m_semaphore, &ti) != 0; + #endif + } } diff --git a/src/Nazara/Core/Posix/SemaphoreImpl.hpp b/src/Nazara/Core/Posix/SemaphoreImpl.hpp index 1708d3be4..c1dedc6b9 100644 --- a/src/Nazara/Core/Posix/SemaphoreImpl.hpp +++ b/src/Nazara/Core/Posix/SemaphoreImpl.hpp @@ -10,19 +10,22 @@ #include #include -class NzSemaphoreImpl +namespace Nz { - public: - NzSemaphoreImpl(unsigned int count); - ~NzSemaphoreImpl(); + class SemaphoreImpl + { + public: + SemaphoreImpl(unsigned int count); + ~SemaphoreImpl(); - unsigned int GetCount() const; - void Post(); - void Wait(); - bool Wait(nzUInt32 timeout); + unsigned int GetCount() const; + void Post(); + void Wait(); + bool Wait(UInt32 timeout); - private: - sem_t m_semaphore; -}; + private: + sem_t m_semaphore; + }; +} #endif // NAZARA_SEMAPHOREIMPL_HPP diff --git a/src/Nazara/Core/Posix/TaskSchedulerImpl.cpp b/src/Nazara/Core/Posix/TaskSchedulerImpl.cpp index 9b0acd270..b04fdcfd9 100644 --- a/src/Nazara/Core/Posix/TaskSchedulerImpl.cpp +++ b/src/Nazara/Core/Posix/TaskSchedulerImpl.cpp @@ -7,186 +7,189 @@ #include #include -bool NzTaskSchedulerImpl::Initialize(unsigned int workerCount) +namespace Nz { - if (IsInitialized()) - return true; // Déjà initialisé - - #if NAZARA_CORE_SAFE - if (workerCount == 0) + bool TaskSchedulerImpl::Initialize(unsigned int workerCount) { - NazaraError("Invalid worker count ! (0)"); - return false; - } - #endif + if (IsInitialized()) + return true; // Déjà initialisé - s_workerCount = workerCount; - s_isDone = false; - s_isWaiting = false; - s_shouldFinish = false; - - s_threads.reset(new pthread_t[workerCount]); - - // On initialise les conditions variables, mutex et barrière. - pthread_cond_init(&s_cvEmpty, nullptr); - pthread_cond_init(&s_cvNotEmpty, nullptr); - pthread_mutex_init(&s_mutexQueue, nullptr); - pthread_barrier_init(&s_barrier, nullptr, workerCount + 1); - - for (unsigned int i = 0; i < s_workerCount; ++i) - { - // Le thread va se lancer, attendre que tous se créent et attendre d'être réveillé. - pthread_create(&s_threads[i], nullptr, WorkerProc, nullptr); - } - - pthread_barrier_wait(&s_barrier); // On attend que les enfants soient bien créés. - - return true; -} - -bool NzTaskSchedulerImpl::IsInitialized() -{ - return s_workerCount > 0; -} - -void NzTaskSchedulerImpl::Run(NzFunctor** tasks, unsigned int count) -{ - // On s'assure que des tâches ne sont pas déjà en cours - Wait(); - - pthread_mutex_lock(&s_mutexQueue); - s_isDone = false; - - while (count--) - s_tasks.push(*tasks++); - - pthread_cond_signal(&s_cvNotEmpty); - pthread_mutex_unlock(&s_mutexQueue); -} - -void NzTaskSchedulerImpl::Uninitialize() -{ - #ifdef NAZARA_CORE_SAFE - if (s_workerCount == 0) - { - NazaraError("Task scheduler is not initialized"); - return; - } - #endif - - // On réveille les threads pour qu'ils sortent de la boucle et terminent. - pthread_mutex_lock(&s_mutexQueue); - // On commence par vider la queue et demander qu'ils s'arrêtent. - std::queue emptyQueue; - std::swap(s_tasks, emptyQueue); - s_shouldFinish = true; - pthread_cond_broadcast(&s_cvNotEmpty); - pthread_mutex_unlock(&s_mutexQueue); - - // On attend que chaque thread se termine - for (unsigned int i = 0; i < s_workerCount; ++i) - pthread_join(s_threads[i], nullptr); - - // Et on libère les ressources - pthread_barrier_destroy(&s_barrier); - pthread_cond_destroy(&s_cvEmpty); - pthread_cond_destroy(&s_cvNotEmpty); - pthread_mutex_destroy(&s_mutexQueue); - - s_workerCount = 0; -} - -void NzTaskSchedulerImpl::WaitForTasks() -{ - #ifdef NAZARA_CORE_SAFE - if (s_workerCount == 0) - { - NazaraError("Task scheduler is not initialized"); - return; - } - #endif - - Wait(); -} - -NzFunctor* NzTaskSchedulerImpl::PopQueue() -{ - NzFunctor* task = nullptr; - - pthread_mutex_lock(&s_mutexQueue); - - if (!s_tasks.empty()) - { - task = s_tasks.front(); - s_tasks.pop(); - } - - pthread_mutex_unlock(&s_mutexQueue); - - return task; -} - -void NzTaskSchedulerImpl::Wait() -{ - if (s_isDone) - return; - - pthread_mutex_lock(&s_mutexQueue); - s_isWaiting = true; - pthread_cond_broadcast(&s_cvNotEmpty); - pthread_cond_wait(&s_cvEmpty, &s_mutexQueue); - pthread_mutex_unlock(&s_mutexQueue); - - s_isDone = true; -} - -void* NzTaskSchedulerImpl::WorkerProc(void* /*userdata*/) -{ - // On s'assure que tous les threads soient correctement lancés. - pthread_barrier_wait(&s_barrier); - - // On quitte s'il doit terminer. - while (!s_shouldFinish) - { - NzFunctor* task = PopQueue(); - - if (task) + #if NAZARA_CORE_SAFE + if (workerCount == 0) { - // On exécute la tâche avant de la supprimer - task->Run(); - delete task; + NazaraError("Invalid worker count ! (0)"); + return false; } - else + #endif + + s_workerCount = workerCount; + s_isDone = false; + s_isWaiting = false; + s_shouldFinish = false; + + s_threads.reset(new pthread_t[workerCount]); + + // On initialise les conditions variables, mutex et barrière. + pthread_cond_init(&s_cvEmpty, nullptr); + pthread_cond_init(&s_cvNotEmpty, nullptr); + pthread_mutex_init(&s_mutexQueue, nullptr); + pthread_barrier_init(&s_barrier, nullptr, workerCount + 1); + + for (unsigned int i = 0; i < s_workerCount; ++i) { - pthread_mutex_lock(&s_mutexQueue); - if (s_tasks.empty()) - s_isDone = true; + // Le thread va se lancer, attendre que tous se créent et attendre d'être réveillé. + pthread_create(&s_threads[i], nullptr, WorkerProc, nullptr); + } - while (!(!s_tasks.empty() || s_isWaiting || s_shouldFinish)) - pthread_cond_wait(&s_cvNotEmpty, &s_mutexQueue); + pthread_barrier_wait(&s_barrier); // On attend que les enfants soient bien créés. - if (s_tasks.empty() && s_isWaiting) + return true; + } + + bool TaskSchedulerImpl::IsInitialized() + { + return s_workerCount > 0; + } + + void TaskSchedulerImpl::Run(Functor** tasks, unsigned int count) + { + // On s'assure que des tâches ne sont pas déjà en cours + Wait(); + + pthread_mutex_lock(&s_mutexQueue); + s_isDone = false; + + while (count--) + s_tasks.push(*tasks++); + + pthread_cond_signal(&s_cvNotEmpty); + pthread_mutex_unlock(&s_mutexQueue); + } + + void TaskSchedulerImpl::Uninitialize() + { + #ifdef NAZARA_CORE_SAFE + if (s_workerCount == 0) + { + NazaraError("Task scheduler is not initialized"); + return; + } + #endif + + // On réveille les threads pour qu'ils sortent de la boucle et terminent. + pthread_mutex_lock(&s_mutexQueue); + // On commence par vider la queue et demander qu'ils s'arrêtent. + std::queue emptyQueue; + std::swap(s_tasks, emptyQueue); + s_shouldFinish = true; + pthread_cond_broadcast(&s_cvNotEmpty); + pthread_mutex_unlock(&s_mutexQueue); + + // On attend que chaque thread se termine + for (unsigned int i = 0; i < s_workerCount; ++i) + pthread_join(s_threads[i], nullptr); + + // Et on libère les ressources + pthread_barrier_destroy(&s_barrier); + pthread_cond_destroy(&s_cvEmpty); + pthread_cond_destroy(&s_cvNotEmpty); + pthread_mutex_destroy(&s_mutexQueue); + + s_workerCount = 0; + } + + void TaskSchedulerImpl::WaitForTasks() + { + #ifdef NAZARA_CORE_SAFE + if (s_workerCount == 0) + { + NazaraError("Task scheduler is not initialized"); + return; + } + #endif + + Wait(); + } + + Functor* TaskSchedulerImpl::PopQueue() + { + Functor* task = nullptr; + + pthread_mutex_lock(&s_mutexQueue); + + if (!s_tasks.empty()) + { + task = s_tasks.front(); + s_tasks.pop(); + } + + pthread_mutex_unlock(&s_mutexQueue); + + return task; + } + + void TaskSchedulerImpl::Wait() + { + if (s_isDone) + return; + + pthread_mutex_lock(&s_mutexQueue); + s_isWaiting = true; + pthread_cond_broadcast(&s_cvNotEmpty); + pthread_cond_wait(&s_cvEmpty, &s_mutexQueue); + pthread_mutex_unlock(&s_mutexQueue); + + s_isDone = true; + } + + void* TaskSchedulerImpl::WorkerProc(void* /*userdata*/) + { + // On s'assure que tous les threads soient correctement lancés. + pthread_barrier_wait(&s_barrier); + + // On quitte s'il doit terminer. + while (!s_shouldFinish) + { + Functor* task = PopQueue(); + + if (task) { - // On prévient le thread qui attend que les tâches soient effectuées. - s_isWaiting = false; - pthread_cond_signal(&s_cvEmpty); + // On exécute la tâche avant de la supprimer + task->Run(); + delete task; } + else + { + pthread_mutex_lock(&s_mutexQueue); + if (s_tasks.empty()) + s_isDone = true; - pthread_mutex_unlock(&s_mutexQueue); + while (!(!s_tasks.empty() || s_isWaiting || s_shouldFinish)) + pthread_cond_wait(&s_cvNotEmpty, &s_mutexQueue); + + if (s_tasks.empty() && s_isWaiting) + { + // On prévient le thread qui attend que les tâches soient effectuées. + s_isWaiting = false; + pthread_cond_signal(&s_cvEmpty); + } + + pthread_mutex_unlock(&s_mutexQueue); + } } + + return nullptr; } - return nullptr; + std::queue TaskSchedulerImpl::s_tasks; + std::unique_ptr TaskSchedulerImpl::s_threads; + std::atomic TaskSchedulerImpl::s_isDone; + std::atomic TaskSchedulerImpl::s_isWaiting; + std::atomic TaskSchedulerImpl::s_shouldFinish; + unsigned int TaskSchedulerImpl::s_workerCount; + + pthread_mutex_t TaskSchedulerImpl::s_mutexQueue; + pthread_cond_t TaskSchedulerImpl::s_cvEmpty; + pthread_cond_t TaskSchedulerImpl::s_cvNotEmpty; + pthread_barrier_t TaskSchedulerImpl::s_barrier; } - -std::queue NzTaskSchedulerImpl::s_tasks; -std::unique_ptr NzTaskSchedulerImpl::s_threads; -std::atomic NzTaskSchedulerImpl::s_isDone; -std::atomic NzTaskSchedulerImpl::s_isWaiting; -std::atomic NzTaskSchedulerImpl::s_shouldFinish; -unsigned int NzTaskSchedulerImpl::s_workerCount; - -pthread_mutex_t NzTaskSchedulerImpl::s_mutexQueue; -pthread_cond_t NzTaskSchedulerImpl::s_cvEmpty; -pthread_cond_t NzTaskSchedulerImpl::s_cvNotEmpty; -pthread_barrier_t NzTaskSchedulerImpl::s_barrier; diff --git a/src/Nazara/Core/Posix/TaskSchedulerImpl.hpp b/src/Nazara/Core/Posix/TaskSchedulerImpl.hpp index 632e65370..e132e4686 100644 --- a/src/Nazara/Core/Posix/TaskSchedulerImpl.hpp +++ b/src/Nazara/Core/Posix/TaskSchedulerImpl.hpp @@ -14,34 +14,37 @@ #include #include -class NzTaskSchedulerImpl +namespace Nz { - public: - NzTaskSchedulerImpl() = delete; - ~NzTaskSchedulerImpl() = delete; + class TaskSchedulerImpl + { + public: + TaskSchedulerImpl() = delete; + ~TaskSchedulerImpl() = delete; - static bool Initialize(unsigned int workerCount); - static bool IsInitialized(); - static void Run(NzFunctor** tasks, unsigned int count); - static void Uninitialize(); - static void WaitForTasks(); + static bool Initialize(unsigned int workerCount); + static bool IsInitialized(); + static void Run(Functor** tasks, unsigned int count); + static void Uninitialize(); + static void WaitForTasks(); - private: - static NzFunctor* PopQueue(); - static void Wait(); - static void* WorkerProc(void* userdata); + private: + static Functor* PopQueue(); + static void Wait(); + static void* WorkerProc(void* userdata); - static std::queue s_tasks; - static std::unique_ptr s_threads; - static std::atomic s_isDone; - static std::atomic s_isWaiting; - static std::atomic s_shouldFinish; - static unsigned int s_workerCount; + static std::queue s_tasks; + static std::unique_ptr s_threads; + static std::atomic s_isDone; + static std::atomic s_isWaiting; + static std::atomic s_shouldFinish; + static unsigned int s_workerCount; - static pthread_mutex_t s_mutexQueue; - static pthread_cond_t s_cvEmpty; - static pthread_cond_t s_cvNotEmpty; - static pthread_barrier_t s_barrier; -}; + static pthread_mutex_t s_mutexQueue; + static pthread_cond_t s_cvEmpty; + static pthread_cond_t s_cvNotEmpty; + static pthread_barrier_t s_barrier; + }; +} #endif // NAZARA_TASKSCHEDULERIMPL_HPP diff --git a/src/Nazara/Core/Posix/ThreadImpl.cpp b/src/Nazara/Core/Posix/ThreadImpl.cpp index 77099e3c0..c16424328 100644 --- a/src/Nazara/Core/Posix/ThreadImpl.cpp +++ b/src/Nazara/Core/Posix/ThreadImpl.cpp @@ -9,64 +9,67 @@ #include #include -NzThreadImpl::NzThreadImpl(NzFunctor* functor) +namespace Nz { - int error = pthread_create(&m_handle, nullptr, &NzThreadImpl::ThreadProc, functor); - if (error != 0) - NazaraInternalError("Failed to create thread: " + NzError::GetLastSystemError()); -} - -void NzThreadImpl::Detach() -{ - pthread_detach(m_handle); -} - -void NzThreadImpl::Join() -{ - pthread_join(m_handle, nullptr); -} - -void* NzThreadImpl::ThreadProc(void* userdata) -{ - NzFunctor* func = static_cast(userdata); - func->Run(); - delete func; - - return nullptr; -} - -void NzThreadImpl::Sleep(nzUInt32 time) -{ - // code from SFML2 Unix SleepImpl.cpp source https://github.com/LaurentGomila/SFML/blob/master/src/SFML/System/Unix/SleepImpl.cpp - - // usleep is not reliable enough (it might block the - // whole process instead of just the current thread) - // so we must use pthread_cond_timedwait instead - - // this implementation is inspired from Qt - - // get the current time - timeval tv; - gettimeofday(&tv, nullptr); - - // construct the time limit (current time + time to wait) - timespec ti; - ti.tv_nsec = (tv.tv_usec + (time % 1000)) * 1000; - ti.tv_sec = tv.tv_sec + (time / 1000) + (ti.tv_nsec / 1000000000); - ti.tv_nsec %= 1000000000; - - // create a mutex and thread condition - pthread_mutex_t mutex; - pthread_mutex_init(&mutex, nullptr); - pthread_cond_t condition; - pthread_cond_init(&condition, nullptr); - - // wait... - pthread_mutex_lock(&mutex); - pthread_cond_timedwait(&condition, &mutex, &ti); - pthread_mutex_unlock(&mutex); - - // destroy the mutex and condition - pthread_cond_destroy(&condition); - pthread_mutex_destroy(&mutex); + ThreadImpl::ThreadImpl(Functor* functor) + { + int error = pthread_create(&m_handle, nullptr, &ThreadImpl::ThreadProc, functor); + if (error != 0) + NazaraInternalError("Failed to create thread: " + Error::GetLastSystemError()); + } + + void ThreadImpl::Detach() + { + pthread_detach(m_handle); + } + + void ThreadImpl::Join() + { + pthread_join(m_handle, nullptr); + } + + void* ThreadImpl::ThreadProc(void* userdata) + { + Functor* func = static_cast(userdata); + func->Run(); + delete func; + + return nullptr; + } + + void ThreadImpl::Sleep(UInt32 time) + { + // code from SFML2 Unix SleepImpl.cpp source https://github.com/LaurentGomila/SFML/blob/master/src/SFML/System/Unix/SleepImpl.cpp + + // usleep is not reliable enough (it might block the + // whole process instead of just the current thread) + // so we must use pthread_cond_timedwait instead + + // this implementation is inspired from Qt + + // get the current time + timeval tv; + gettimeofday(&tv, nullptr); + + // construct the time limit (current time + time to wait) + timespec ti; + ti.tv_nsec = (tv.tv_usec + (time % 1000)) * 1000; + ti.tv_sec = tv.tv_sec + (time / 1000) + (ti.tv_nsec / 1000000000); + ti.tv_nsec %= 1000000000; + + // create a mutex and thread condition + pthread_mutex_t mutex; + pthread_mutex_init(&mutex, nullptr); + pthread_cond_t condition; + pthread_cond_init(&condition, nullptr); + + // wait... + pthread_mutex_lock(&mutex); + pthread_cond_timedwait(&condition, &mutex, &ti); + pthread_mutex_unlock(&mutex); + + // destroy the mutex and condition + pthread_cond_destroy(&condition); + pthread_mutex_destroy(&mutex); + } } diff --git a/src/Nazara/Core/Posix/ThreadImpl.hpp b/src/Nazara/Core/Posix/ThreadImpl.hpp index f1674d902..1ed6f3c8a 100644 --- a/src/Nazara/Core/Posix/ThreadImpl.hpp +++ b/src/Nazara/Core/Posix/ThreadImpl.hpp @@ -10,22 +10,25 @@ #include #include -struct NzFunctor; - -class NzThreadImpl +namespace Nz { - public: - NzThreadImpl(NzFunctor* threadFunc); + struct Functor; - void Detach(); - void Join(); + class ThreadImpl + { + public: + ThreadImpl(Functor* threadFunc); - static void Sleep(nzUInt32 time); + void Detach(); + void Join(); - private: - static void* ThreadProc(void* userdata); + static void Sleep(UInt32 time); - pthread_t m_handle; -}; + private: + static void* ThreadProc(void* userdata); + + pthread_t m_handle; + }; +} #endif // NAZARA_THREADIMPL_HPP diff --git a/src/Nazara/Graphics/Debug/NewOverload.cpp b/src/Nazara/Graphics/Debug/NewOverload.cpp index 3cd2de7dc..6c5b5c8f0 100644 --- a/src/Nazara/Graphics/Debug/NewOverload.cpp +++ b/src/Nazara/Graphics/Debug/NewOverload.cpp @@ -10,22 +10,22 @@ void* operator new(std::size_t size) { - return NzMemoryManager::Allocate(size, false); + return Nz::MemoryManager::Allocate(size, false); } void* operator new[](std::size_t size) { - return NzMemoryManager::Allocate(size, true); + return Nz::MemoryManager::Allocate(size, true); } void operator delete(void* pointer) noexcept { - NzMemoryManager::Free(pointer, false); + Nz::MemoryManager::Free(pointer, false); } void operator delete[](void* pointer) noexcept { - NzMemoryManager::Free(pointer, true); + Nz::MemoryManager::Free(pointer, true); } #endif // NAZARA_GRAPHICS_MANAGE_MEMORY diff --git a/src/Nazara/Graphics/ForwardRenderTechnique.cpp b/src/Nazara/Graphics/ForwardRenderTechnique.cpp index 75768a3fa..6eeb41575 100644 --- a/src/Nazara/Graphics/ForwardRenderTechnique.cpp +++ b/src/Nazara/Graphics/ForwardRenderTechnique.cpp @@ -689,7 +689,7 @@ namespace Nz // On envoie les lumières directionnelles s'il y a (Les mêmes pour tous) if (shaderUniforms->hasLightUniforms) { - lightCount = std::min(m_renderQueue.directionalLights.size(), NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U)); + lightCount = std::min(m_renderQueue.directionalLights.size(), static_cast(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS)); for (unsigned int i = 0; i < lightCount; ++i) SendLightUniforms(shader, shaderUniforms->lightUniforms, i, shaderUniforms->lightOffset * i); diff --git a/src/Nazara/Lua/Debug/NewOverload.cpp b/src/Nazara/Lua/Debug/NewOverload.cpp index 2f0f42402..e7cf94bd6 100644 --- a/src/Nazara/Lua/Debug/NewOverload.cpp +++ b/src/Nazara/Lua/Debug/NewOverload.cpp @@ -10,22 +10,22 @@ void* operator new(std::size_t size) { - return NzMemoryManager::Allocate(size, false); + return Nz::MemoryManager::Allocate(size, false); } void* operator new[](std::size_t size) { - return NzMemoryManager::Allocate(size, true); + return Nz::MemoryManager::Allocate(size, true); } void operator delete(void* pointer) noexcept { - NzMemoryManager::Free(pointer, false); + Nz::MemoryManager::Free(pointer, false); } void operator delete[](void* pointer) noexcept { - NzMemoryManager::Free(pointer, true); + Nz::MemoryManager::Free(pointer, true); } #endif // NAZARA_LUA_MANAGE_MEMORY diff --git a/src/Nazara/Noise/Debug/NewOverload.cpp b/src/Nazara/Noise/Debug/NewOverload.cpp index a8b96c450..1e2da7321 100644 --- a/src/Nazara/Noise/Debug/NewOverload.cpp +++ b/src/Nazara/Noise/Debug/NewOverload.cpp @@ -10,22 +10,22 @@ void* operator new(std::size_t size) { - return NzMemoryManager::Allocate(size, false); + return Nz::MemoryManager::Allocate(size, false); } void* operator new[](std::size_t size) { - return NzMemoryManager::Allocate(size, true); + return Nz::MemoryManager::Allocate(size, true); } void operator delete(void* pointer) noexcept { - NzMemoryManager::Free(pointer, false); + Nz::MemoryManager::Free(pointer, false); } void operator delete[](void* pointer) noexcept { - NzMemoryManager::Free(pointer, true); + Nz::MemoryManager::Free(pointer, true); } #endif // NAZARA_NOISE_MANAGE_MEMORY diff --git a/src/Nazara/Physics/Debug/NewOverload.cpp b/src/Nazara/Physics/Debug/NewOverload.cpp index 4e991cb2c..b7ca2c243 100644 --- a/src/Nazara/Physics/Debug/NewOverload.cpp +++ b/src/Nazara/Physics/Debug/NewOverload.cpp @@ -10,22 +10,22 @@ void* operator new(std::size_t size) { - return NzMemoryManager::Allocate(size, false); + return Nz::MemoryManager::Allocate(size, false); } void* operator new[](std::size_t size) { - return NzMemoryManager::Allocate(size, true); + return Nz::MemoryManager::Allocate(size, true); } void operator delete(void* pointer) noexcept { - NzMemoryManager::Free(pointer, false); + Nz::MemoryManager::Free(pointer, false); } void operator delete[](void* pointer) noexcept { - NzMemoryManager::Free(pointer, true); + Nz::MemoryManager::Free(pointer, true); } #endif // NAZARA_PHYSICS_MANAGE_MEMORY diff --git a/src/Nazara/Renderer/Context.cpp b/src/Nazara/Renderer/Context.cpp index ada25df91..69919d094 100644 --- a/src/Nazara/Renderer/Context.cpp +++ b/src/Nazara/Renderer/Context.cpp @@ -14,7 +14,7 @@ #if defined(NAZARA_PLATFORM_WINDOWS) #include -#elif defined(NAZARA_PLATFORM_LINUX) +#elif defined(NAZARA_PLATFORM_GLX) #include #define CALLBACK #else diff --git a/src/Nazara/Renderer/Debug/NewOverload.cpp b/src/Nazara/Renderer/Debug/NewOverload.cpp index 72563a400..6ef952271 100644 --- a/src/Nazara/Renderer/Debug/NewOverload.cpp +++ b/src/Nazara/Renderer/Debug/NewOverload.cpp @@ -10,22 +10,22 @@ void* operator new(std::size_t size) { - return NzMemoryManager::Allocate(size, false); + return Nz::MemoryManager::Allocate(size, false); } void* operator new[](std::size_t size) { - return NzMemoryManager::Allocate(size, true); + return Nz::MemoryManager::Allocate(size, true); } void operator delete(void* pointer) noexcept { - NzMemoryManager::Free(pointer, false); + Nz::MemoryManager::Free(pointer, false); } void operator delete[](void* pointer) noexcept { - NzMemoryManager::Free(pointer, true); + Nz::MemoryManager::Free(pointer, true); } #endif // NAZARA_RENDERER_MANAGE_MEMORY diff --git a/src/Nazara/Renderer/GLX/ContextImpl.cpp b/src/Nazara/Renderer/GLX/ContextImpl.cpp index 967305d7d..8bff9793a 100644 --- a/src/Nazara/Renderer/GLX/ContextImpl.cpp +++ b/src/Nazara/Renderer/GLX/ContextImpl.cpp @@ -12,286 +12,289 @@ using namespace GLX; -namespace +namespace Nz { - Display* m_display; - int m_sharedDisplay = 0; - - bool ctxErrorOccurred = false; - int ctxErrorHandler( Display* /*dpy*/, XErrorEvent* /*ev*/ ) + namespace { - ctxErrorOccurred = true; - return 0; + Display* m_display; + int m_sharedDisplay = 0; + + bool ctxErrorOccurred = false; + int ctxErrorHandler( Display* /*dpy*/, XErrorEvent* /*ev*/ ) + { + ctxErrorOccurred = true; + return 0; + } } -} -NzContextImpl::NzContextImpl() : -m_colormap(0), -m_context(0), -m_window(0), -m_ownsWindow(false) -{ - if (m_sharedDisplay == 0) - m_display = XOpenDisplay(nullptr); - - ++m_sharedDisplay; -} - -NzContextImpl::~NzContextImpl() -{ - Destroy(); - - if (--m_sharedDisplay == 0) + ContextImpl::ContextImpl() : + m_colormap(0), + m_context(0), + m_window(0), + m_ownsWindow(false) { - XCloseDisplay(m_display); - m_display = nullptr; + if (m_sharedDisplay == 0) + m_display = XOpenDisplay(nullptr); + + ++m_sharedDisplay; } -} -bool NzContextImpl::Activate() -{ - return glXMakeCurrent(m_display, m_window, m_context) == true; -} - -bool NzContextImpl::Create(NzContextParameters& parameters) -{ - // En cas d'exception, la ressource sera quand même libérée - NzCallOnExit onExit([this] () + ContextImpl::~ContextImpl() { Destroy(); - }); - // Get a matching FB config - static int visual_attribs[] = - { - GLX_X_RENDERABLE, True, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, - GLX_BUFFER_SIZE, parameters.bitsPerPixel, - GLX_ALPHA_SIZE, (parameters.bitsPerPixel == 32) ? 8 : 0, - GLX_DEPTH_SIZE, parameters.depthBits, - GLX_STENCIL_SIZE, parameters.stencilBits, - GLX_DOUBLEBUFFER, True, - GLX_SAMPLE_BUFFERS, (parameters.antialiasingLevel > 0) ? True : False, - GLX_SAMPLES, parameters.antialiasingLevel, - None - }; - - int glx_major = 0; - int glx_minor = 0; - // FBConfigs were added in GLX version 1.3. - if (!glXQueryVersion(m_display, &glx_major, &glx_minor) || ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) - { - NazaraError("Invalid GLX version, version > 1.3 is required."); - return false; - } - - int fbcount; - GLXFBConfig* fbc = glXChooseFBConfig(m_display, XDefaultScreen(m_display), visual_attribs, &fbcount); - if (!fbc) - { - NazaraError("Failed to retrieve a framebuffer config"); - return false; - } - - // Pick the FB config/visual with the most samples per pixel - int best_fbc = -1; - int worst_fbc = -1; - int best_num_samp = -1; - int worst_num_samp = 999; - - for (int i = 0; i < fbcount; ++i) - { - XVisualInfo* vi = glXGetVisualFromFBConfig(m_display, fbc[i]); - - if (vi) + if (--m_sharedDisplay == 0) { - int samp_buf = 0, samples = 0; - glXGetFBConfigAttrib(m_display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); - glXGetFBConfigAttrib(m_display, fbc[i], GLX_SAMPLES , &samples ); - - if ((best_fbc < 0) || (samp_buf && (samples > best_num_samp))) - { - best_fbc = i; - best_num_samp = samples; - } - if ((worst_fbc < 0) || !samp_buf || (samples < worst_num_samp)) - { - worst_fbc = i; - worst_num_samp = samples; - } + XCloseDisplay(m_display); + m_display = nullptr; } - XFree(vi); } - GLXFBConfig bestFbc = fbc[best_fbc]; - - // Be sure to free the FBConfig list allocated by glXChooseFBConfig() - XFree(fbc); - - // Get a visual - XVisualInfo* vi = glXGetVisualFromFBConfig(m_display, bestFbc); - if (!vi) + bool ContextImpl::Activate() { - NazaraError("Failed to get best VisualInfo"); - return false; + return glXMakeCurrent(m_display, m_window, m_context) == true; } - // If context is shared by multiple windows - if (parameters.window) + bool ContextImpl::Create(ContextParameters& parameters) { - m_window = parameters.window; - m_ownsWindow = false; - } - else - { - XSetWindowAttributes swa; - swa.colormap = m_colormap = XCreateColormap( - m_display, - XRootWindow( - m_display, - vi->screen), - vi->visual, - AllocNone - ); - - swa.background_pixmap = None; - swa.border_pixel = 0; - swa.event_mask = StructureNotifyMask; - - if (!m_colormap) + // En cas d'exception, la ressource sera quand même libérée + CallOnExit onExit([this] () { - NazaraError("Failed to create colormap for context"); + Destroy(); + }); + + // Get a matching FB config + static int visual_attribs[] = + { + GLX_X_RENDERABLE, True, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + GLX_BUFFER_SIZE, parameters.bitsPerPixel, + GLX_ALPHA_SIZE, (parameters.bitsPerPixel == 32) ? 8 : 0, + GLX_DEPTH_SIZE, parameters.depthBits, + GLX_STENCIL_SIZE, parameters.stencilBits, + GLX_DOUBLEBUFFER, True, + GLX_SAMPLE_BUFFERS, (parameters.antialiasingLevel > 0) ? True : False, + GLX_SAMPLES, parameters.antialiasingLevel, + None + }; + + int glx_major = 0; + int glx_minor = 0; + // FBConfigs were added in GLX version 1.3. + if (!glXQueryVersion(m_display, &glx_major, &glx_minor) || ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) + { + NazaraError("Invalid GLX version, version > 1.3 is required."); return false; } - m_window = XCreateWindow( - m_display, - XRootWindow( - m_display, - vi->screen), - 0, 0, // X, Y - 1, 1, // W H - 0, - vi->depth, - InputOutput, - vi->visual, - CWBorderPixel | CWColormap | CWEventMask, - &swa - ); - - m_ownsWindow = true; - } - - if (!m_window) - { - NazaraError("Failed to create window"); - return false; - } - - // Done with the visual info data - XFree(vi); - - // Install an X error handler so the application won't exit if GL 3.0 - // context allocation fails. - // - // Note this error handler is global. All display connections in all threads - // of a process use the same error handler, so be sure to guard against other - // threads issuing X commands while this code is running. - ctxErrorOccurred = false; - int (*oldHandler)(Display*, XErrorEvent*) = - XSetErrorHandler(&ctxErrorHandler); - - // Check for the GLX_ARB_create_context extension string and the function. - // If either is not present, use GLX 1.3 context creation method. - if (!glXCreateContextAttribs) - { - NazaraWarning("glXCreateContextAttribs() not found. Using old-style GLX context"); - m_context = glXCreateNewContext(m_display, bestFbc, GLX_RGBA_TYPE, parameters.shared ? parameters.shareContext->m_impl->m_context : 0, True); - } - // If it does, try to get a GL 3.0 context! - else - { - int profile = parameters.compatibilityProfile ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : GLX_CONTEXT_CORE_PROFILE_BIT_ARB; - int debug = parameters.debugMode ? GLX_CONTEXT_DEBUG_BIT_ARB : 0; - - int major = 3;//parameters.majorVersion; - int minor = 3;//parameters.minorVersion; - - int context_attribs[] = + int fbcount; + GLXFBConfig* fbc = glXChooseFBConfig(m_display, XDefaultScreen(m_display), visual_attribs, &fbcount); + if (!fbc) { - GLX_CONTEXT_MAJOR_VERSION_ARB, major, - GLX_CONTEXT_MINOR_VERSION_ARB, minor, - GLX_CONTEXT_PROFILE_MASK_ARB, profile, - GLX_CONTEXT_FLAGS_ARB, debug, - None, None - }; + NazaraError("Failed to retrieve a framebuffer config"); + return false; + } - m_context = glXCreateContextAttribs( - m_display, - bestFbc, - parameters.shared ? parameters.shareContext->m_impl->m_context : 0, - True, - context_attribs - ); + // Pick the FB config/visual with the most samples per pixel + int best_fbc = -1; + int worst_fbc = -1; + int best_num_samp = -1; + int worst_num_samp = 999; + + for (int i = 0; i < fbcount; ++i) + { + XVisualInfo* vi = glXGetVisualFromFBConfig(m_display, fbc[i]); + + if (vi) + { + int samp_buf = 0, samples = 0; + glXGetFBConfigAttrib(m_display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); + glXGetFBConfigAttrib(m_display, fbc[i], GLX_SAMPLES , &samples ); + + if ((best_fbc < 0) || (samp_buf && (samples > best_num_samp))) + { + best_fbc = i; + best_num_samp = samples; + } + if ((worst_fbc < 0) || !samp_buf || (samples < worst_num_samp)) + { + worst_fbc = i; + worst_num_samp = samples; + } + } + XFree(vi); + } + + GLXFBConfig bestFbc = fbc[best_fbc]; + + // Be sure to free the FBConfig list allocated by glXChooseFBConfig() + XFree(fbc); + + // Get a visual + XVisualInfo* vi = glXGetVisualFromFBConfig(m_display, bestFbc); + if (!vi) + { + NazaraError("Failed to get best VisualInfo"); + return false; + } + + // If context is shared by multiple windows + if (parameters.window) + { + m_window = parameters.window; + m_ownsWindow = false; + } + else + { + XSetWindowAttributes swa; + swa.colormap = m_colormap = XCreateColormap( + m_display, + XRootWindow( + m_display, + vi->screen), + vi->visual, + AllocNone + ); + + swa.background_pixmap = None; + swa.border_pixel = 0; + swa.event_mask = StructureNotifyMask; + + if (!m_colormap) + { + NazaraError("Failed to create colormap for context"); + return false; + } + + m_window = XCreateWindow( + m_display, + XRootWindow( + m_display, + vi->screen), + 0, 0, // X, Y + 1, 1, // W H + 0, + vi->depth, + InputOutput, + vi->visual, + CWBorderPixel | CWColormap | CWEventMask, + &swa + ); + + m_ownsWindow = true; + } + + if (!m_window) + { + NazaraError("Failed to create window"); + return false; + } + + // Done with the visual info data + XFree(vi); + + // Install an X error handler so the application won't exit if GL 3.0 + // context allocation fails. + // + // Note this error handler is global. All display connections in all threads + // of a process use the same error handler, so be sure to guard against other + // threads issuing X commands while this code is running. + ctxErrorOccurred = false; + int (*oldHandler)(Display*, XErrorEvent*) = + XSetErrorHandler(&ctxErrorHandler); + + // Check for the GLX_ARB_create_context extension string and the function. + // If either is not present, use GLX 1.3 context creation method. + if (!glXCreateContextAttribs) + { + NazaraWarning("glXCreateContextAttribs() not found. Using old-style GLX context"); + m_context = glXCreateNewContext(m_display, bestFbc, GLX_RGBA_TYPE, parameters.shared ? parameters.shareContext->m_impl->m_context : 0, True); + } + // If it does, try to get a GL 3.0 context! + else + { + int profile = parameters.compatibilityProfile ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + int debug = parameters.debugMode ? GLX_CONTEXT_DEBUG_BIT_ARB : 0; + + int major = 3;//parameters.majorVersion; + int minor = 3;//parameters.minorVersion; + + int context_attribs[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, major, + GLX_CONTEXT_MINOR_VERSION_ARB, minor, + GLX_CONTEXT_PROFILE_MASK_ARB, profile, + GLX_CONTEXT_FLAGS_ARB, debug, + None, None + }; + + m_context = glXCreateContextAttribs( + m_display, + bestFbc, + parameters.shared ? parameters.shareContext->m_impl->m_context : 0, + True, + context_attribs + ); + } + + // Sync to ensure any errors generated are processed. + XSync(m_display, False); + XSetErrorHandler(oldHandler); + if (ctxErrorOccurred || !m_context) + { + NazaraError("Failed to create context, check the version"); + return false; + } + + onExit.Reset(); + + return true; } - // Sync to ensure any errors generated are processed. - XSync(m_display, False); - XSetErrorHandler(oldHandler); - if (ctxErrorOccurred || !m_context) + void ContextImpl::Destroy() { - NazaraError("Failed to create context, check the version"); - return false; + // Destroy the context + if (m_context) + { + if (glXGetCurrentContext() == m_context) + glXMakeCurrent(m_display, None, nullptr); + glXDestroyContext(m_display, m_context); + m_context = nullptr; + } + + // Destroy the window if we own it + if (m_ownsWindow && m_window) + { + XFreeColormap(m_display, m_colormap); + XDestroyWindow(m_display, m_window); + m_ownsWindow = false; + m_window = 0; + XFlush(m_display); + } } - onExit.Reset(); - - return true; -} - -void NzContextImpl::Destroy() -{ - // Destroy the context - if (m_context) + void ContextImpl::EnableVerticalSync(bool enabled) { - if (glXGetCurrentContext() == m_context) - glXMakeCurrent(m_display, None, nullptr); - glXDestroyContext(m_display, m_context); - m_context = nullptr; + if (glXSwapIntervalEXT) + glXSwapIntervalEXT(m_display, glXGetCurrentDrawable(), enabled ? 1 : 0); + else if (NzglXSwapIntervalMESA) + NzglXSwapIntervalMESA(enabled ? 1 : 0); + else if (glXSwapIntervalSGI) + glXSwapIntervalSGI(enabled ? 1 : 0); + else + NazaraError("Vertical sync not supported"); } - // Destroy the window if we own it - if (m_ownsWindow && m_window) + void ContextImpl::SwapBuffers() { - XFreeColormap(m_display, m_colormap); - XDestroyWindow(m_display, m_window); - m_ownsWindow = false; - m_window = 0; - XFlush(m_display); + if (m_window) + glXSwapBuffers(m_display, m_window); + } + + bool ContextImpl::Desactivate() + { + return glXMakeCurrent(m_display, None, nullptr) == true; } } - -void NzContextImpl::EnableVerticalSync(bool enabled) -{ - if (glXSwapIntervalEXT) - glXSwapIntervalEXT(m_display, glXGetCurrentDrawable(), enabled ? 1 : 0); - else if (NzglXSwapIntervalMESA) - NzglXSwapIntervalMESA(enabled ? 1 : 0); - else if (glXSwapIntervalSGI) - glXSwapIntervalSGI(enabled ? 1 : 0); - else - NazaraError("Vertical sync not supported"); -} - -void NzContextImpl::SwapBuffers() -{ - if (m_window) - glXSwapBuffers(m_display, m_window); -} - -bool NzContextImpl::Desactivate() -{ - return glXMakeCurrent(m_display, None, nullptr) == true; -} diff --git a/src/Nazara/Renderer/GLX/ContextImpl.hpp b/src/Nazara/Renderer/GLX/ContextImpl.hpp index 0a3a8b8dc..40bbd5fc7 100644 --- a/src/Nazara/Renderer/GLX/ContextImpl.hpp +++ b/src/Nazara/Renderer/GLX/ContextImpl.hpp @@ -9,31 +9,34 @@ #include -class NzContextParameters; - -class NzContextImpl +namespace Nz { - public: - NzContextImpl(); - ~NzContextImpl(); + class ContextParameters; - bool Activate(); + class ContextImpl + { + public: + ContextImpl(); + ~ContextImpl(); - bool Create(NzContextParameters& parameters); + bool Activate(); - void Destroy(); + bool Create(ContextParameters& parameters); - void EnableVerticalSync(bool enabled); + void Destroy(); - void SwapBuffers(); + void EnableVerticalSync(bool enabled); - static bool Desactivate(); + void SwapBuffers(); - private: - GLX::Colormap m_colormap; - GLX::GLXContext m_context; - GLX::Window m_window; - bool m_ownsWindow; -}; + static bool Desactivate(); + + private: + GLX::Colormap m_colormap; + GLX::GLXContext m_context; + GLX::Window m_window; + bool m_ownsWindow; + }; +} #endif // NAZARA_CONTEXTIMPL_HPP diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index c1e0e544e..5cc0865ea 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -9,6 +9,9 @@ #include #include #include +#if defined(NAZARA_PLATFORM_GLX) +#include +#endif // NAZARA_PLATFORM_GLX #include #include #include @@ -30,7 +33,7 @@ namespace Nz OpenGLFunc entry = reinterpret_cast(wglGetProcAddress(name)); if (!entry) // wglGetProcAddress ne fonctionne pas sur les fonctions OpenGL <= 1.1 entry = reinterpret_cast(GetProcAddress(openGLlibrary, name)); - #elif defined(NAZARA_PLATFORM_LINUX) + #elif defined(NAZARA_PLATFORM_GLX) OpenGLFunc entry = reinterpret_cast(GLX::glXGetProcAddress(reinterpret_cast(name))); #else #error OS not handled @@ -716,6 +719,15 @@ namespace Nz if (s_initialized) return true; + #if defined(NAZARA_PLATFORM_GLX) + Initializer display; + if (!display) + { + NazaraError("Failed to load display library"); + return false; + } + #endif + if (!LoadLibrary()) { NazaraError("Failed to load OpenGL library"); @@ -1004,7 +1016,7 @@ namespace Nz wglGetExtensionsStringARB = reinterpret_cast(LoadEntry("wglGetExtensionsStringARB", false)); wglGetExtensionsStringEXT = reinterpret_cast(LoadEntry("wglGetExtensionsStringEXT", false)); wglSwapInterval = reinterpret_cast(LoadEntry("wglSwapIntervalEXT", false)); - #elif defined(NAZARA_PLATFORM_LINUX) + #elif defined(NAZARA_PLATFORM_GLX) glXSwapIntervalEXT = reinterpret_cast(LoadEntry("glXSwapIntervalEXT", false)); NzglXSwapIntervalMESA = reinterpret_cast(LoadEntry("glXSwapIntervalMESA", false)); glXSwapIntervalSGI = reinterpret_cast(LoadEntry("glXSwapIntervalSGI", false)); @@ -2242,9 +2254,9 @@ PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr; PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = nullptr; PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT = nullptr; PFNWGLSWAPINTERVALEXTPROC wglSwapInterval = nullptr; -#elif defined(NAZARA_PLATFORM_LINUX) +#elif defined(NAZARA_PLATFORM_GLX) GLX::PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = nullptr; GLX::PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = nullptr; GLX::PFNGLXSWAPINTERVALMESAPROC NzglXSwapIntervalMESA = nullptr; GLX::PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr; -#endif \ No newline at end of file +#endif diff --git a/src/Nazara/Utility/Debug/NewOverload.cpp b/src/Nazara/Utility/Debug/NewOverload.cpp index 0ab389a70..00dc7f90c 100644 --- a/src/Nazara/Utility/Debug/NewOverload.cpp +++ b/src/Nazara/Utility/Debug/NewOverload.cpp @@ -10,22 +10,22 @@ void* operator new(std::size_t size) { - return NzMemoryManager::Allocate(size, false); + return Nz::MemoryManager::Allocate(size, false); } void* operator new[](std::size_t size) { - return NzMemoryManager::Allocate(size, true); + return Nz::MemoryManager::Allocate(size, true); } void operator delete(void* pointer) noexcept { - NzMemoryManager::Free(pointer, false); + Nz::MemoryManager::Free(pointer, false); } void operator delete[](void* pointer) noexcept { - NzMemoryManager::Free(pointer, true); + Nz::MemoryManager::Free(pointer, true); } #endif // NAZARA_UTILITY_MANAGE_MEMORY diff --git a/src/Nazara/Utility/X11/CursorImpl.cpp b/src/Nazara/Utility/X11/CursorImpl.cpp index 1ccde5e70..8cdde5170 100644 --- a/src/Nazara/Utility/X11/CursorImpl.cpp +++ b/src/Nazara/Utility/X11/CursorImpl.cpp @@ -12,150 +12,153 @@ #include #include -bool NzCursorImpl::Create(const NzImage& cursor, int hotSpotX, int hotSpotY) +namespace Nz { - NzImage cursorImage(cursor); // Vive le COW - if (!cursorImage.Convert(nzPixelFormat_BGRA8)) + bool CursorImpl::Create(const Image& cursor, int hotSpotX, int hotSpotY) { - NazaraError("Failed to convert cursor to BGRA8"); - return false; - } + Image cursorImage(cursor); // Vive le COW + if (!cursorImage.Convert(Nz::PixelFormatType_BGRA8)) + { + NazaraError("Failed to convert cursor to BGRA8"); + return false; + } - auto width = cursorImage.GetWidth(); - auto height = cursorImage.GetHeight(); + auto width = cursorImage.GetWidth(); + auto height = cursorImage.GetHeight(); - NzScopedXCBConnection connection; + ScopedXCBConnection connection; - xcb_screen_t* screen = X11::XCBDefaultScreen(connection); + xcb_screen_t* screen = X11::XCBDefaultScreen(connection); - NzScopedXCB error(nullptr); - NzScopedXCB formatsReply = xcb_render_query_pict_formats_reply( - connection, - xcb_render_query_pict_formats(connection), - &error); - - if (!formatsReply || error) - { - NazaraError("Failed to get pict formats"); - return false; - } - - xcb_render_pictforminfo_t* fmt = xcb_render_util_find_standard_format( - formatsReply.get(), - XCB_PICT_STANDARD_ARGB_32); - - if (!fmt) - { - NazaraError("Failed to find format PICT_STANDARD_ARGB_32"); - return false; - } - - xcb_image_t* xi = xcb_image_create( - width, height, - XCB_IMAGE_FORMAT_Z_PIXMAP, - 32, 32, 32, 32, - XCB_IMAGE_ORDER_LSB_FIRST, - XCB_IMAGE_ORDER_MSB_FIRST, - 0, 0, 0); - - if (!xi) - { - NazaraError("Failed to create image for cursor"); - return false; - } - - std::unique_ptr data(new uint8_t[xi->stride * height]); - - if (!data) - { - xcb_image_destroy(xi); - NazaraError("Failed to allocate memory for cursor image"); - return false; - } - - xi->data = data.get(); - - std::copy(cursorImage.GetConstPixels(), cursorImage.GetConstPixels() + cursorImage.GetBytesPerPixel() * width * height, xi->data); - - xcb_render_picture_t pic = XCB_NONE; - - NzCallOnExit onExit([&](){ - xcb_image_destroy(xi); - if (pic != XCB_NONE) - xcb_render_free_picture(connection, pic); - }); - - NzXCBPixmap pix(connection); - if (!pix.Create(32, screen->root, width, height)) - { - NazaraError("Failed to create pixmap for cursor"); - return false; - } - - pic = xcb_generate_id(connection); - if (!X11::CheckCookie( - connection, - xcb_render_create_picture( + ScopedXCB error(nullptr); + ScopedXCB formatsReply = xcb_render_query_pict_formats_reply( connection, - pic, - pix, - fmt->id, - 0, - nullptr - ))) - { - NazaraError("Failed to create render picture for cursor"); - return false; - } + xcb_render_query_pict_formats(connection), + &error); - NzXCBGContext gc(connection); - if (!gc.Create(pix, 0, nullptr)) - { - NazaraError("Failed to create gcontext for cursor"); - return false; - } + if (!formatsReply || error) + { + NazaraError("Failed to get pict formats"); + return false; + } - if (!X11::CheckCookie( - connection, - xcb_image_put( + xcb_render_pictforminfo_t* fmt = xcb_render_util_find_standard_format( + formatsReply.get(), + XCB_PICT_STANDARD_ARGB_32); + + if (!fmt) + { + NazaraError("Failed to find format PICT_STANDARD_ARGB_32"); + return false; + } + + xcb_image_t* xi = xcb_image_create( + width, height, + XCB_IMAGE_FORMAT_Z_PIXMAP, + 32, 32, 32, 32, + XCB_IMAGE_ORDER_LSB_FIRST, + XCB_IMAGE_ORDER_MSB_FIRST, + 0, 0, 0); + + if (!xi) + { + NazaraError("Failed to create image for cursor"); + return false; + } + + std::unique_ptr data(new uint8_t[xi->stride * height]); + + if (!data) + { + xcb_image_destroy(xi); + NazaraError("Failed to allocate memory for cursor image"); + return false; + } + + xi->data = data.get(); + + std::copy(cursorImage.GetConstPixels(), cursorImage.GetConstPixels() + cursorImage.GetBytesPerPixel() * width * height, xi->data); + + xcb_render_picture_t pic = XCB_NONE; + + CallOnExit onExit([&](){ + xcb_image_destroy(xi); + if (pic != XCB_NONE) + xcb_render_free_picture(connection, pic); + }); + + XCBPixmap pix(connection); + if (!pix.Create(32, screen->root, width, height)) + { + NazaraError("Failed to create pixmap for cursor"); + return false; + } + + pic = xcb_generate_id(connection); + if (!X11::CheckCookie( connection, - pix, - gc, - xi, - 0, 0, - 0 - ))) - { - NazaraError("Failed to put image for cursor"); - return false; - } + xcb_render_create_picture( + connection, + pic, + pix, + fmt->id, + 0, + nullptr + ))) + { + NazaraError("Failed to create render picture for cursor"); + return false; + } - m_cursor = xcb_generate_id(connection); - if (!X11::CheckCookie( - connection, - xcb_render_create_cursor( + XCBGContext gc(connection); + if (!gc.Create(pix, 0, nullptr)) + { + NazaraError("Failed to create gcontext for cursor"); + return false; + } + + if (!X11::CheckCookie( connection, - m_cursor, - pic, - hotSpotX, hotSpotY - ))) - { - NazaraError("Failed to create cursor"); - return false; + xcb_image_put( + connection, + pix, + gc, + xi, + 0, 0, + 0 + ))) + { + NazaraError("Failed to put image for cursor"); + return false; + } + + m_cursor = xcb_generate_id(connection); + if (!X11::CheckCookie( + connection, + xcb_render_create_cursor( + connection, + m_cursor, + pic, + hotSpotX, hotSpotY + ))) + { + NazaraError("Failed to create cursor"); + return false; + } + + return true; } - return true; -} + void CursorImpl::Destroy() + { + ScopedXCBConnection connection; -void NzCursorImpl::Destroy() -{ - NzScopedXCBConnection connection; + xcb_free_cursor(connection, m_cursor); + m_cursor = 0; + } - xcb_free_cursor(connection, m_cursor); - m_cursor = 0; -} - -xcb_cursor_t NzCursorImpl::GetCursor() -{ - return m_cursor; + xcb_cursor_t CursorImpl::GetCursor() + { + return m_cursor; + } } diff --git a/src/Nazara/Utility/X11/CursorImpl.hpp b/src/Nazara/Utility/X11/CursorImpl.hpp index b20555623..41d91bcb1 100644 --- a/src/Nazara/Utility/X11/CursorImpl.hpp +++ b/src/Nazara/Utility/X11/CursorImpl.hpp @@ -7,20 +7,24 @@ #ifndef NAZARA_CURSORIMPL_HPP #define NAZARA_CURSORIMPL_HPP +#include #include -class NzImage; - -class NzCursorImpl +namespace Nz { - public: - bool Create(const NzImage& image, int hotSpotX, int hotSpotY); - void Destroy(); + class Image; - xcb_cursor_t GetCursor(); + class CursorImpl + { + public: + bool Create(const Image& image, int hotSpotX, int hotSpotY); + void Destroy(); - private: - xcb_cursor_t m_cursor; -}; + xcb_cursor_t GetCursor(); + + private: + xcb_cursor_t m_cursor; + }; +} #endif // NAZARA_CURSORIMPL_HPP diff --git a/src/Nazara/Utility/X11/Display.cpp b/src/Nazara/Utility/X11/Display.cpp index 99e0abe03..d61543dfd 100644 --- a/src/Nazara/Utility/X11/Display.cpp +++ b/src/Nazara/Utility/X11/Display.cpp @@ -4,32 +4,34 @@ #include #include +#include +#include #include #include #include -namespace +namespace Nz { - // The shared display and its reference counter - xcb_connection_t* sharedConnection = nullptr; - int screen_nbr = 0; - unsigned int referenceCountConnection = 0; - - xcb_key_symbols_t* sharedkeySymbol; - unsigned int referenceCountKeySymbol = 0; - - xcb_ewmh_connection_t* sharedEwmhConnection; - unsigned int referenceCountEwmhConnection = 0; - - using AtomMap = std::map; - AtomMap atoms; -} - -namespace X11 -{ - bool CheckCookie(xcb_connection_t* connection, xcb_void_cookie_t cookie) + namespace { - NzScopedXCB error(xcb_request_check( + // The shared display and its reference counter + xcb_connection_t* sharedConnection = nullptr; + int screen_nbr = 0; + unsigned int referenceCountConnection = 0; + + xcb_key_symbols_t* sharedkeySymbol = nullptr; + unsigned int referenceCountKeySymbol = 0; + + xcb_ewmh_connection_t* sharedEwmhConnection = nullptr; + unsigned int referenceCountEwmhConnection = 0; + + using AtomMap = std::map; + AtomMap atoms; + } + + bool X11::CheckCookie(xcb_connection_t* connection, xcb_void_cookie_t cookie) + { + ScopedXCB error(xcb_request_check( connection, cookie )); @@ -40,36 +42,36 @@ namespace X11 return true; } - void CloseConnection(xcb_connection_t* connection) + void X11::CloseConnection(xcb_connection_t* connection) { NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server"); --referenceCountConnection; } - void CloseEWMHConnection(xcb_ewmh_connection_t* ewmh_connection) + void X11::CloseEWMHConnection(xcb_ewmh_connection_t* ewmh_connection) { NazaraAssert(ewmh_connection == sharedEwmhConnection, "The model is meant for one connection to X11 server"); --referenceCountEwmhConnection; } - xcb_atom_t GetAtom(const std::string& name, bool onlyIfExists) + xcb_atom_t X11::GetAtom(const String& name, bool onlyIfExists) { AtomMap::const_iterator iter = atoms.find(name); if (iter != atoms.end()) return iter->second; - NzScopedXCB error(nullptr); + ScopedXCB error(nullptr); xcb_connection_t* connection = OpenConnection(); - NzScopedXCB reply(xcb_intern_atom_reply( + ScopedXCB reply(xcb_intern_atom_reply( connection, xcb_intern_atom( connection, onlyIfExists, - name.size(), - name.c_str() + name.GetSize(), + name.GetConstBuffer() ), &error )); @@ -87,8 +89,16 @@ namespace X11 return reply->atom; } - void Initialize() + bool X11::Initialize() { + if (IsInitialized()) + { + s_moduleReferenceCounter++; + return true; // Déjà initialisé + } + + s_moduleReferenceCounter++; + NazaraAssert(referenceCountConnection == 0, "Initialize should be called before anything"); NazaraAssert(referenceCountKeySymbol == 0, "Initialize should be called before anything"); NazaraAssert(referenceCountEwmhConnection == 0, "Initialize should be called before anything"); @@ -125,9 +135,17 @@ namespace X11 OpenEWMHConnection(sharedConnection); } + + NazaraNotice("Initialized: Utility module"); + return true; } - xcb_key_symbols_t* XCBKeySymbolsAlloc(xcb_connection_t* connection) + bool X11::IsInitialized() + { + return s_moduleReferenceCounter != 0; + } + + xcb_key_symbols_t* X11::XCBKeySymbolsAlloc(xcb_connection_t* connection) { NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server"); @@ -135,20 +153,20 @@ namespace X11 return sharedkeySymbol; } - void XCBKeySymbolsFree(xcb_key_symbols_t* keySymbols) + void X11::XCBKeySymbolsFree(xcb_key_symbols_t* keySymbols) { NazaraAssert(keySymbols == sharedkeySymbol, "The model is meant for one connection to X11 server"); --referenceCountKeySymbol; } - xcb_connection_t* OpenConnection() + xcb_connection_t* X11::OpenConnection() { ++referenceCountConnection; return sharedConnection; } - xcb_ewmh_connection_t* OpenEWMHConnection(xcb_connection_t* connection) + xcb_ewmh_connection_t* X11::OpenEWMHConnection(xcb_connection_t* connection) { NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server"); @@ -156,8 +174,19 @@ namespace X11 return sharedEwmhConnection; } - void Uninitialize() + void X11::Uninitialize() { + if (s_moduleReferenceCounter != 1) + { + // Le module est soit encore utilisé, soit pas initialisé + if (s_moduleReferenceCounter > 1) + s_moduleReferenceCounter--; + + return; + } + + s_moduleReferenceCounter = 0; + { NazaraAssert(referenceCountEwmhConnection == 1, "Uninitialize should be called after anything or a close is missing"); CloseEWMHConnection(sharedEwmhConnection); @@ -179,9 +208,11 @@ namespace X11 xcb_disconnect(sharedConnection); } + + NazaraNotice("Uninitialized: Display module"); } - xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection) + xcb_window_t X11::XCBDefaultRootWindow(xcb_connection_t* connection) { NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server"); xcb_screen_t* screen = XCBDefaultScreen(connection); @@ -190,19 +221,19 @@ namespace X11 return XCB_NONE; } - xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection) + xcb_screen_t* X11::XCBDefaultScreen(xcb_connection_t* connection) { NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server"); return XCBScreenOfDisplay(connection, screen_nbr); } - int XCBScreen(xcb_connection_t* connection) + int X11::XCBScreen(xcb_connection_t* connection) { NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server"); return screen_nbr; } - xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr) + xcb_screen_t* X11::XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr) { NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server"); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(connection)); @@ -215,4 +246,6 @@ namespace X11 return nullptr; } + + unsigned int X11::s_moduleReferenceCounter = 0; } diff --git a/src/Nazara/Utility/X11/Display.hpp b/src/Nazara/Utility/X11/Display.hpp index a1b0e56e5..95177e2d2 100644 --- a/src/Nazara/Utility/X11/Display.hpp +++ b/src/Nazara/Utility/X11/Display.hpp @@ -7,35 +7,47 @@ #ifndef NAZARA_X11DISPLAY_HPP #define NAZARA_X11DISPLAY_HPP +#include #include #include -#include -#include typedef struct _XCBKeySymbols xcb_key_symbols_t; -namespace X11 +namespace Nz { - bool CheckCookie(xcb_connection_t* connection, xcb_void_cookie_t cookie); - void CloseConnection(xcb_connection_t* connection); - void CloseEWMHConnection(xcb_ewmh_connection_t* ewmh_connection); + class String; - xcb_atom_t GetAtom(const std::string& name, bool onlyIfExists = false); + class X11 + { + public: + X11() = delete; + ~X11() = delete; - void Initialize(); + static bool CheckCookie(xcb_connection_t* connection, xcb_void_cookie_t cookie); + static void CloseConnection(xcb_connection_t* connection); + static void CloseEWMHConnection(xcb_ewmh_connection_t* ewmh_connection); - xcb_key_symbols_t* XCBKeySymbolsAlloc(xcb_connection_t* connection); - void XCBKeySymbolsFree(xcb_key_symbols_t* keySymbols); + static xcb_atom_t GetAtom(const String& name, bool onlyIfExists = false); - xcb_connection_t* OpenConnection(); - xcb_ewmh_connection_t* OpenEWMHConnection(xcb_connection_t* connection); + static bool Initialize(); + static bool IsInitialized(); - void Uninitialize(); + static xcb_key_symbols_t* XCBKeySymbolsAlloc(xcb_connection_t* connection); + static void XCBKeySymbolsFree(xcb_key_symbols_t* keySymbols); - xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection); - xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection); - int XCBScreen(xcb_connection_t* connection); - xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr); + static xcb_connection_t* OpenConnection(); + static xcb_ewmh_connection_t* OpenEWMHConnection(xcb_connection_t* connection); + + static void Uninitialize(); + + static xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection); + static xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection); + static int XCBScreen(xcb_connection_t* connection); + static xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr); + + private: + static unsigned int s_moduleReferenceCounter; + }; } #endif // NAZARA_X11DISPLAY_HPP diff --git a/src/Nazara/Utility/X11/IconImpl.cpp b/src/Nazara/Utility/X11/IconImpl.cpp index 3eb3bd1ab..030cbdf8b 100644 --- a/src/Nazara/Utility/X11/IconImpl.cpp +++ b/src/Nazara/Utility/X11/IconImpl.cpp @@ -10,125 +10,128 @@ #include #include -NzIconImpl::NzIconImpl() +namespace Nz { - NzScopedXCBConnection connection; - - m_iconPixmap.Connect(connection); - m_maskPixmap.Connect(connection); -} - -bool NzIconImpl::Create(const NzImage& icon) -{ - NzImage iconImage(icon); // Vive le COW - if (!iconImage.Convert(nzPixelFormat_BGRA8)) + IconImpl::IconImpl() { - NazaraError("Failed to convert icon to BGRA8"); - return false; + ScopedXCBConnection connection; + + m_iconPixmap.Connect(connection); + m_maskPixmap.Connect(connection); } - auto width = iconImage.GetWidth(); - auto height = iconImage.GetHeight(); - - NzScopedXCBConnection connection; - - xcb_screen_t* screen = X11::XCBDefaultScreen(connection); - - if (!m_iconPixmap.Create( - screen->root_depth, - screen->root, - width, - height)) + bool IconImpl::Create(const Image& icon) { - NazaraError("Failed to create icon pixmap"); - return false; - } - - NzCallOnExit onExit([this](){ - Destroy(); - }); - - NzXCBGContext iconGC(connection); - - if (!iconGC.Create( - m_iconPixmap, - 0, - nullptr)) - { - NazaraError("Failed to create icon gc"); - return false; - } - - if (!X11::CheckCookie( - connection, - xcb_put_image( - connection, - XCB_IMAGE_FORMAT_Z_PIXMAP, - m_iconPixmap, - iconGC, - width, - height, - 0, - 0, - 0, - screen->root_depth, - width * height * 4, - iconImage.GetConstPixels() - ))) - { - NazaraError("Failed to put image for icon"); - return false; - } - - // Create the mask pixmap (must have 1 bit depth) - std::size_t pitch = (width + 7) / 8; - static std::vector maskPixels(pitch * height, 0); - for (std::size_t j = 0; j < height; ++j) - { - for (std::size_t i = 0; i < pitch; ++i) + Image iconImage(icon); // Vive le COW + if (!iconImage.Convert(Nz::PixelFormatType_BGRA8)) { - for (std::size_t k = 0; k < 8; ++k) + NazaraError("Failed to convert icon to BGRA8"); + return false; + } + + auto width = iconImage.GetWidth(); + auto height = iconImage.GetHeight(); + + ScopedXCBConnection connection; + + xcb_screen_t* screen = X11::XCBDefaultScreen(connection); + + if (!m_iconPixmap.Create( + screen->root_depth, + screen->root, + width, + height)) + { + NazaraError("Failed to create icon pixmap"); + return false; + } + + CallOnExit onExit([this](){ + Destroy(); + }); + + XCBGContext iconGC(connection); + + if (!iconGC.Create( + m_iconPixmap, + 0, + nullptr)) + { + NazaraError("Failed to create icon gc"); + return false; + } + + if (!X11::CheckCookie( + connection, + xcb_put_image( + connection, + XCB_IMAGE_FORMAT_Z_PIXMAP, + m_iconPixmap, + iconGC, + width, + height, + 0, + 0, + 0, + screen->root_depth, + width * height * 4, + iconImage.GetConstPixels() + ))) + { + NazaraError("Failed to put image for icon"); + return false; + } + + // Create the mask pixmap (must have 1 bit depth) + std::size_t pitch = (width + 7) / 8; + static std::vector maskPixels(pitch * height, 0); + for (std::size_t j = 0; j < height; ++j) + { + for (std::size_t i = 0; i < pitch; ++i) { - if (i * 8 + k < width) + for (std::size_t k = 0; k < 8; ++k) { - nzUInt8 opacity = (iconImage.GetConstPixels()[(i * 8 + k + j * width) * 4 + 3] > 0) ? 1 : 0; - maskPixels[i + j * pitch] |= (opacity << k); + if (i * 8 + k < width) + { + UInt8 opacity = (iconImage.GetConstPixels()[(i * 8 + k + j * width) * 4 + 3] > 0) ? 1 : 0; + maskPixels[i + j * pitch] |= (opacity << k); + } } } } + + if (!m_maskPixmap.CreatePixmapFromBitmapData( + X11::XCBDefaultRootWindow(connection), + reinterpret_cast(&maskPixels[0]), + width, + height, + 1, + 0, + 1, + nullptr)) + { + NazaraError("Failed to create mask pixmap for icon"); + return false; + } + + onExit.Reset(); + + return true; } - if (!m_maskPixmap.CreatePixmapFromBitmapData( - X11::XCBDefaultRootWindow(connection), - reinterpret_cast(&maskPixels[0]), - width, - height, - 1, - 0, - 1, - nullptr)) + void IconImpl::Destroy() { - NazaraError("Failed to create mask pixmap for icon"); - return false; + m_iconPixmap.Destroy(); + m_maskPixmap.Destroy(); } - onExit.Reset(); + xcb_pixmap_t IconImpl::GetIcon() + { + return m_iconPixmap; + } - return true; -} - -void NzIconImpl::Destroy() -{ - m_iconPixmap.Destroy(); - m_maskPixmap.Destroy(); -} - -xcb_pixmap_t NzIconImpl::GetIcon() -{ - return m_iconPixmap; -} - -xcb_pixmap_t NzIconImpl::GetMask() -{ - return m_maskPixmap; + xcb_pixmap_t IconImpl::GetMask() + { + return m_maskPixmap; + } } diff --git a/src/Nazara/Utility/X11/IconImpl.hpp b/src/Nazara/Utility/X11/IconImpl.hpp index bf968f367..1e8b301bc 100644 --- a/src/Nazara/Utility/X11/IconImpl.hpp +++ b/src/Nazara/Utility/X11/IconImpl.hpp @@ -7,24 +7,28 @@ #ifndef NAZARA_ICONIMPL_HPP #define NAZARA_ICONIMPL_HPP +#include #include -class NzImage; - -class NzIconImpl +namespace Nz { - public: - NzIconImpl(); + class Image; - bool Create(const NzImage& image); - void Destroy(); + class IconImpl + { + public: + IconImpl(); - xcb_pixmap_t GetIcon(); - xcb_pixmap_t GetMask(); + bool Create(const Image& image); + void Destroy(); - private: - NzXCBPixmap m_iconPixmap; - NzXCBPixmap m_maskPixmap; -}; + xcb_pixmap_t GetIcon(); + xcb_pixmap_t GetMask(); + + private: + XCBPixmap m_iconPixmap; + XCBPixmap m_maskPixmap; + }; +} #endif // NAZARA_ICONIMPL_HPP diff --git a/src/Nazara/Utility/X11/InputImpl.cpp b/src/Nazara/Utility/X11/InputImpl.cpp index 442b1e544..e21fdae96 100644 --- a/src/Nazara/Utility/X11/InputImpl.cpp +++ b/src/Nazara/Utility/X11/InputImpl.cpp @@ -12,215 +12,186 @@ #include #include -namespace +namespace Nz { - - KeySym GetKeySym(NzKeyboard::Key key) + namespace { - // X11 keysym correspondant - KeySym keysym = 0; - switch (key) + KeySym GetKeySym(Keyboard::Key key) { - // Lettres - case NzKeyboard::A: keysym = XK_A; break; - case NzKeyboard::B: keysym = XK_B; break; - case NzKeyboard::C: keysym = XK_C; break; - case NzKeyboard::D: keysym = XK_D; break; - case NzKeyboard::E: keysym = XK_E; break; - case NzKeyboard::F: keysym = XK_F; break; - case NzKeyboard::G: keysym = XK_G; break; - case NzKeyboard::H: keysym = XK_H; break; - case NzKeyboard::I: keysym = XK_I; break; - case NzKeyboard::J: keysym = XK_J; break; - case NzKeyboard::K: keysym = XK_K; break; - case NzKeyboard::L: keysym = XK_L; break; - case NzKeyboard::M: keysym = XK_M; break; - case NzKeyboard::N: keysym = XK_N; break; - case NzKeyboard::O: keysym = XK_O; break; - case NzKeyboard::P: keysym = XK_P; break; - case NzKeyboard::Q: keysym = XK_Q; break; - case NzKeyboard::R: keysym = XK_R; break; - case NzKeyboard::S: keysym = XK_S; break; - case NzKeyboard::T: keysym = XK_T; break; - case NzKeyboard::U: keysym = XK_U; break; - case NzKeyboard::V: keysym = XK_V; break; - case NzKeyboard::W: keysym = XK_W; break; - case NzKeyboard::X: keysym = XK_X; break; - case NzKeyboard::Y: keysym = XK_Y; break; - case NzKeyboard::Z: keysym = XK_Z; break; + // X11 keysym correspondant + KeySym keysym = 0; + switch (key) + { + // Lettres + case Keyboard::A: keysym = XK_A; break; + case Keyboard::B: keysym = XK_B; break; + case Keyboard::C: keysym = XK_C; break; + case Keyboard::D: keysym = XK_D; break; + case Keyboard::E: keysym = XK_E; break; + case Keyboard::F: keysym = XK_F; break; + case Keyboard::G: keysym = XK_G; break; + case Keyboard::H: keysym = XK_H; break; + case Keyboard::I: keysym = XK_I; break; + case Keyboard::J: keysym = XK_J; break; + case Keyboard::K: keysym = XK_K; break; + case Keyboard::L: keysym = XK_L; break; + case Keyboard::M: keysym = XK_M; break; + case Keyboard::N: keysym = XK_N; break; + case Keyboard::O: keysym = XK_O; break; + case Keyboard::P: keysym = XK_P; break; + case Keyboard::Q: keysym = XK_Q; break; + case Keyboard::R: keysym = XK_R; break; + case Keyboard::S: keysym = XK_S; break; + case Keyboard::T: keysym = XK_T; break; + case Keyboard::U: keysym = XK_U; break; + case Keyboard::V: keysym = XK_V; break; + case Keyboard::W: keysym = XK_W; break; + case Keyboard::X: keysym = XK_X; break; + case Keyboard::Y: keysym = XK_Y; break; + case Keyboard::Z: keysym = XK_Z; break; - // Touches de fonction - case NzKeyboard::F1: keysym = XK_F1; break; - case NzKeyboard::F2: keysym = XK_F2; break; - case NzKeyboard::F3: keysym = XK_F3; break; - case NzKeyboard::F4: keysym = XK_F4; break; - case NzKeyboard::F5: keysym = XK_F5; break; - case NzKeyboard::F6: keysym = XK_F6; break; - case NzKeyboard::F7: keysym = XK_F7; break; - case NzKeyboard::F8: keysym = XK_F8; break; - case NzKeyboard::F9: keysym = XK_F9; break; - case NzKeyboard::F10: keysym = XK_F10; break; - case NzKeyboard::F11: keysym = XK_F11; break; - case NzKeyboard::F12: keysym = XK_F12; break; - case NzKeyboard::F13: keysym = XK_F13; break; - case NzKeyboard::F14: keysym = XK_F14; break; - case NzKeyboard::F15: keysym = XK_F15; break; + // Touches de fonction + case Keyboard::F1: keysym = XK_F1; break; + case Keyboard::F2: keysym = XK_F2; break; + case Keyboard::F3: keysym = XK_F3; break; + case Keyboard::F4: keysym = XK_F4; break; + case Keyboard::F5: keysym = XK_F5; break; + case Keyboard::F6: keysym = XK_F6; break; + case Keyboard::F7: keysym = XK_F7; break; + case Keyboard::F8: keysym = XK_F8; break; + case Keyboard::F9: keysym = XK_F9; break; + case Keyboard::F10: keysym = XK_F10; break; + case Keyboard::F11: keysym = XK_F11; break; + case Keyboard::F12: keysym = XK_F12; break; + case Keyboard::F13: keysym = XK_F13; break; + case Keyboard::F14: keysym = XK_F14; break; + case Keyboard::F15: keysym = XK_F15; break; - // Flèches directionnelles - case NzKeyboard::Down: keysym = XK_Down; break; - case NzKeyboard::Left: keysym = XK_Left; break; - case NzKeyboard::Right: keysym = XK_Right; break; - case NzKeyboard::Up: keysym = XK_Up; break; + // Flèches directionnelles + case Keyboard::Down: keysym = XK_Down; break; + case Keyboard::Left: keysym = XK_Left; break; + case Keyboard::Right: keysym = XK_Right; break; + case Keyboard::Up: keysym = XK_Up; break; - // Pavé numérique - case NzKeyboard::Add: keysym = XK_KP_Add; break; - case NzKeyboard::Decimal: keysym = XK_KP_Decimal; break; - case NzKeyboard::Divide: keysym = XK_KP_Divide; break; - case NzKeyboard::Multiply: keysym = XK_KP_Multiply; break; - case NzKeyboard::Numpad0: keysym = XK_KP_0; break; - case NzKeyboard::Numpad1: keysym = XK_KP_1; break; - case NzKeyboard::Numpad2: keysym = XK_KP_2; break; - case NzKeyboard::Numpad3: keysym = XK_KP_3; break; - case NzKeyboard::Numpad4: keysym = XK_KP_4; break; - case NzKeyboard::Numpad5: keysym = XK_KP_5; break; - case NzKeyboard::Numpad6: keysym = XK_KP_6; break; - case NzKeyboard::Numpad7: keysym = XK_KP_7; break; - case NzKeyboard::Numpad8: keysym = XK_KP_8; break; - case NzKeyboard::Numpad9: keysym = XK_KP_9; break; - case NzKeyboard::Subtract: keysym = XK_KP_Subtract; break; + // Pavé numérique + case Keyboard::Add: keysym = XK_KP_Add; break; + case Keyboard::Decimal: keysym = XK_KP_Decimal; break; + case Keyboard::Divide: keysym = XK_KP_Divide; break; + case Keyboard::Multiply: keysym = XK_KP_Multiply; break; + case Keyboard::Numpad0: keysym = XK_KP_0; break; + case Keyboard::Numpad1: keysym = XK_KP_1; break; + case Keyboard::Numpad2: keysym = XK_KP_2; break; + case Keyboard::Numpad3: keysym = XK_KP_3; break; + case Keyboard::Numpad4: keysym = XK_KP_4; break; + case Keyboard::Numpad5: keysym = XK_KP_5; break; + case Keyboard::Numpad6: keysym = XK_KP_6; break; + case Keyboard::Numpad7: keysym = XK_KP_7; break; + case Keyboard::Numpad8: keysym = XK_KP_8; break; + case Keyboard::Numpad9: keysym = XK_KP_9; break; + case Keyboard::Subtract: keysym = XK_KP_Subtract; break; - // Divers - case NzKeyboard::Backslash: keysym = XK_backslash; break; - case NzKeyboard::Backspace: keysym = XK_BackSpace; break; - case NzKeyboard::Clear: keysym = XK_Clear; break; - case NzKeyboard::Comma: keysym = XK_comma; break; - case NzKeyboard::Dash: keysym = XK_minus; break; - case NzKeyboard::Delete: keysym = XK_Delete; break; - case NzKeyboard::End: keysym = XK_End; break; - case NzKeyboard::Equal: keysym = XK_equal; break; - case NzKeyboard::Escape: keysym = XK_Escape; break; - case NzKeyboard::Home: keysym = XK_Home; break; - case NzKeyboard::Insert: keysym = XK_Insert; break; - case NzKeyboard::LAlt: keysym = XK_Alt_L; break; - case NzKeyboard::LBracket: keysym = XK_bracketleft; break; - case NzKeyboard::LControl: keysym = XK_Control_L; break; - case NzKeyboard::LShift: keysym = XK_Shift_L; break; - case NzKeyboard::LSystem: keysym = XK_Super_L; break; - case NzKeyboard::Num0: keysym = XK_0; break; - case NzKeyboard::Num1: keysym = XK_1; break; - case NzKeyboard::Num2: keysym = XK_2; break; - case NzKeyboard::Num3: keysym = XK_3; break; - case NzKeyboard::Num4: keysym = XK_4; break; - case NzKeyboard::Num5: keysym = XK_5; break; - case NzKeyboard::Num6: keysym = XK_6; break; - case NzKeyboard::Num7: keysym = XK_7; break; - case NzKeyboard::Num8: keysym = XK_8; break; - case NzKeyboard::Num9: keysym = XK_9; break; - case NzKeyboard::PageDown: keysym = XK_Page_Down; break; - case NzKeyboard::PageUp: keysym = XK_Page_Up; break; - case NzKeyboard::Pause: keysym = XK_Pause; break; - case NzKeyboard::Period: keysym = XK_period; break; - case NzKeyboard::Print: keysym = XK_Print; break; - case NzKeyboard::PrintScreen: keysym = XK_Sys_Req; break; - case NzKeyboard::Quote: keysym = XK_quotedbl; break; - case NzKeyboard::RAlt: keysym = XK_Alt_R; break; - case NzKeyboard::RBracket: keysym = XK_bracketright; break; - case NzKeyboard::RControl: keysym = XK_Control_R; break; - case NzKeyboard::Return: keysym = XK_Return; break; - case NzKeyboard::RShift: keysym = XK_Shift_R; break; - case NzKeyboard::RSystem: keysym = XK_Super_R; break; - case NzKeyboard::Semicolon: keysym = XK_semicolon; break; - case NzKeyboard::Slash: keysym = XK_slash; break; - case NzKeyboard::Space: keysym = XK_space; break; - case NzKeyboard::Tab: keysym = XK_Tab; break; - case NzKeyboard::Tilde: keysym = XK_grave; break; + // Divers + case Keyboard::Backslash: keysym = XK_backslash; break; + case Keyboard::Backspace: keysym = XK_BackSpace; break; + case Keyboard::Clear: keysym = XK_Clear; break; + case Keyboard::Comma: keysym = XK_comma; break; + case Keyboard::Dash: keysym = XK_minus; break; + case Keyboard::Delete: keysym = XK_Delete; break; + case Keyboard::End: keysym = XK_End; break; + case Keyboard::Equal: keysym = XK_equal; break; + case Keyboard::Escape: keysym = XK_Escape; break; + case Keyboard::Home: keysym = XK_Home; break; + case Keyboard::Insert: keysym = XK_Insert; break; + case Keyboard::LAlt: keysym = XK_Alt_L; break; + case Keyboard::LBracket: keysym = XK_bracketleft; break; + case Keyboard::LControl: keysym = XK_Control_L; break; + case Keyboard::LShift: keysym = XK_Shift_L; break; + case Keyboard::LSystem: keysym = XK_Super_L; break; + case Keyboard::Num0: keysym = XK_0; break; + case Keyboard::Num1: keysym = XK_1; break; + case Keyboard::Num2: keysym = XK_2; break; + case Keyboard::Num3: keysym = XK_3; break; + case Keyboard::Num4: keysym = XK_4; break; + case Keyboard::Num5: keysym = XK_5; break; + case Keyboard::Num6: keysym = XK_6; break; + case Keyboard::Num7: keysym = XK_7; break; + case Keyboard::Num8: keysym = XK_8; break; + case Keyboard::Num9: keysym = XK_9; break; + case Keyboard::PageDown: keysym = XK_Page_Down; break; + case Keyboard::PageUp: keysym = XK_Page_Up; break; + case Keyboard::Pause: keysym = XK_Pause; break; + case Keyboard::Period: keysym = XK_period; break; + case Keyboard::Print: keysym = XK_Print; break; + case Keyboard::PrintScreen: keysym = XK_Sys_Req; break; + case Keyboard::Quote: keysym = XK_quotedbl; break; + case Keyboard::RAlt: keysym = XK_Alt_R; break; + case Keyboard::RBracket: keysym = XK_bracketright; break; + case Keyboard::RControl: keysym = XK_Control_R; break; + case Keyboard::Return: keysym = XK_Return; break; + case Keyboard::RShift: keysym = XK_Shift_R; break; + case Keyboard::RSystem: keysym = XK_Super_R; break; + case Keyboard::Semicolon: keysym = XK_semicolon; break; + case Keyboard::Slash: keysym = XK_slash; break; + case Keyboard::Space: keysym = XK_space; break; + case Keyboard::Tab: keysym = XK_Tab; break; + case Keyboard::Tilde: keysym = XK_grave; break; - // Touches navigateur - case NzKeyboard::Browser_Back: keysym = XF86XK_Back; break; - case NzKeyboard::Browser_Favorites: keysym = XF86XK_Favorites; break; - case NzKeyboard::Browser_Forward: keysym = XF86XK_Forward; break; - case NzKeyboard::Browser_Home: keysym = XF86XK_HomePage; break; - case NzKeyboard::Browser_Refresh: keysym = XF86XK_Refresh; break; - case NzKeyboard::Browser_Search: keysym = XF86XK_Search; break; - case NzKeyboard::Browser_Stop: keysym = XF86XK_Stop; break; + // Touches navigateur + case Keyboard::Browser_Back: keysym = XF86XK_Back; break; + case Keyboard::Browser_Favorites: keysym = XF86XK_Favorites; break; + case Keyboard::Browser_Forward: keysym = XF86XK_Forward; break; + case Keyboard::Browser_Home: keysym = XF86XK_HomePage; break; + case Keyboard::Browser_Refresh: keysym = XF86XK_Refresh; break; + case Keyboard::Browser_Search: keysym = XF86XK_Search; break; + case Keyboard::Browser_Stop: keysym = XF86XK_Stop; break; - // Touches de contrôle - case NzKeyboard::Media_Next: keysym = XF86XK_AudioNext; break; - case NzKeyboard::Media_Play: keysym = XF86XK_AudioPlay; break; - case NzKeyboard::Media_Previous: keysym = XF86XK_AudioPrev; break; - case NzKeyboard::Media_Stop: keysym = XF86XK_AudioStop; break; + // Touches de contrôle + case Keyboard::Media_Next: keysym = XF86XK_AudioNext; break; + case Keyboard::Media_Play: keysym = XF86XK_AudioPlay; break; + case Keyboard::Media_Previous: keysym = XF86XK_AudioPrev; break; + case Keyboard::Media_Stop: keysym = XF86XK_AudioStop; break; - // Touches de contrôle du volume - case NzKeyboard::Volume_Down: keysym = XF86XK_AudioLowerVolume; break; - case NzKeyboard::Volume_Mute: keysym = XF86XK_AudioMute; break; - case NzKeyboard::Volume_Up: keysym = XF86XK_AudioRaiseVolume; break; + // Touches de contrôle du volume + case Keyboard::Volume_Down: keysym = XF86XK_AudioLowerVolume; break; + case Keyboard::Volume_Mute: keysym = XF86XK_AudioMute; break; + case Keyboard::Volume_Up: keysym = XF86XK_AudioRaiseVolume; break; - // Touches à verrouillage - case NzKeyboard::CapsLock: keysym = XK_Caps_Lock; break; - case NzKeyboard::NumLock: keysym = XK_Num_Lock; break; - case NzKeyboard::ScrollLock: keysym = XK_Scroll_Lock; break; + // Touches à verrouillage + case Keyboard::CapsLock: keysym = XK_Caps_Lock; break; + case Keyboard::NumLock: keysym = XK_Num_Lock; break; + case Keyboard::ScrollLock: keysym = XK_Scroll_Lock; break; - default: break; + default: break; + } + + // Sanity checks + if (key < 0 || key >= Keyboard::Count || keysym == 0) + NazaraWarning("Key " + String::Number(key) + " is not handled in Keyboard"); + + return keysym; } - - // Sanity checks - if (key < 0 || key >= NzKeyboard::Count || keysym == 0) - NazaraWarning("Key " + NzString::Number(key) + " is not handled in NzKeyboard"); - - return keysym; - } -} - -NzString NzEventImpl::GetKeyName(NzKeyboard::Key key) -{ - KeySym keySym = GetKeySym(key); - - // XKeysymToString returns a static area. - return XKeysymToString(keySym); -} - -NzVector2i NzEventImpl::GetMousePosition() -{ - NzScopedXCBConnection connection; - - NzScopedXCB error(nullptr); - - NzScopedXCB pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( - connection, - X11::XCBDefaultRootWindow(connection) - ), - &error - ) - ); - - if (error) - { - NazaraError("Failed to query pointer"); - return NzVector2i(-1, -1); } - return NzVector2i(pointer->root_x, pointer->root_y); -} - -NzVector2i NzEventImpl::GetMousePosition(const NzWindow& relativeTo) -{ - NzWindowHandle handle = relativeTo.GetHandle(); - if (handle) + String EventImpl::GetKeyName(Keyboard::Key key) { - // Open a connection with the X server - NzScopedXCBConnection connection; + KeySym keySym = GetKeySym(key); - NzScopedXCB error(nullptr); + // XKeysymToString returns a static area. + return XKeysymToString(keySym); + } - NzScopedXCB pointer( + Vector2i EventImpl::GetMousePosition() + { + ScopedXCBConnection connection; + + ScopedXCB error(nullptr); + + ScopedXCB pointer( xcb_query_pointer_reply( connection, xcb_query_pointer( connection, - handle + X11::XCBDefaultRootWindow(connection) ), &error ) @@ -229,143 +200,174 @@ NzVector2i NzEventImpl::GetMousePosition(const NzWindow& relativeTo) if (error) { NazaraError("Failed to query pointer"); - return NzVector2i(-1, -1); + return Vector2i(-1, -1); } - return NzVector2i(pointer->win_x, pointer->win_y); + return Vector2i(pointer->root_x, pointer->root_y); } - else + + Vector2i EventImpl::GetMousePosition(const Window& relativeTo) { - NazaraError("No window handle"); - return NzVector2i(-1, -1); + WindowHandle handle = relativeTo.GetHandle(); + if (handle) + { + // Open a connection with the X server + ScopedXCBConnection connection; + + ScopedXCB error(nullptr); + + ScopedXCB pointer( + xcb_query_pointer_reply( + connection, + xcb_query_pointer( + connection, + handle + ), + &error + ) + ); + + if (error) + { + NazaraError("Failed to query pointer"); + return Vector2i(-1, -1); + } + + return Vector2i(pointer->win_x, pointer->win_y); + } + else + { + NazaraError("No window handle"); + return Vector2i(-1, -1); + } } -} -bool NzEventImpl::IsKeyPressed(NzKeyboard::Key key) -{ - NzScopedXCBConnection connection; - - xcb_keysym_t keySym = GetKeySym(key); - - xcb_key_symbols_t* keySymbols = X11::XCBKeySymbolsAlloc(connection); - if (!keySymbols) + bool EventImpl::IsKeyPressed(Keyboard::Key key) { - NazaraError("Failed to alloc key symbols"); - return false; - } + ScopedXCBConnection connection; - NzScopedXCB keyCode = xcb_key_symbols_get_keycode(keySymbols, keySym); - if (!keyCode) - { - NazaraError("Failed to get key code"); - return false; - } - X11::XCBKeySymbolsFree(keySymbols); + xcb_keysym_t keySym = GetKeySym(key); - NzScopedXCB error(nullptr); + xcb_key_symbols_t* keySymbols = X11::XCBKeySymbolsAlloc(connection); + if (!keySymbols) + { + NazaraError("Failed to alloc key symbols"); + return false; + } - // Get the whole keyboard state - NzScopedXCB keymap( - xcb_query_keymap_reply( - connection, - xcb_query_keymap(connection), - &error - ) - ); + ScopedXCB keyCode = xcb_key_symbols_get_keycode(keySymbols, keySym); + if (!keyCode) + { + NazaraError("Failed to get key code"); + return false; + } + X11::XCBKeySymbolsFree(keySymbols); - if (error) - { - NazaraError("Failed to query keymap"); - return false; - } + ScopedXCB error(nullptr); - // Check our keycode - return (keymap->keys[*keyCode.get() / 8] & (1 << (*keyCode.get() % 8))) != 0; -} - -bool NzEventImpl::IsMouseButtonPressed(NzMouse::Button button) -{ - NzScopedXCBConnection connection; - - NzScopedXCB error(nullptr); - - // Get pointer mask - NzScopedXCB pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( + // Get the whole keyboard state + ScopedXCB keymap( + xcb_query_keymap_reply( connection, - X11::XCBDefaultRootWindow(connection) - ), - &error - ) - ); + xcb_query_keymap(connection), + &error + ) + ); - if (error) + if (error) + { + NazaraError("Failed to query keymap"); + return false; + } + + // Check our keycode + return (keymap->keys[*keyCode.get() / 8] & (1 << (*keyCode.get() % 8))) != 0; + } + + bool EventImpl::IsMouseButtonPressed(Mouse::Button button) { - NazaraError("Failed to query pointer"); + ScopedXCBConnection connection; + + ScopedXCB error(nullptr); + + // Get pointer mask + ScopedXCB pointer( + xcb_query_pointer_reply( + connection, + xcb_query_pointer( + connection, + X11::XCBDefaultRootWindow(connection) + ), + &error + ) + ); + + if (error) + { + NazaraError("Failed to query pointer"); + return false; + } + + uint16_t buttons = pointer->mask; + + switch (button) + { + case Mouse::Left: return buttons & XCB_BUTTON_MASK_1; + case Mouse::Right: return buttons & XCB_BUTTON_MASK_3; + case Mouse::Middle: return buttons & XCB_BUTTON_MASK_2; + case Mouse::XButton1: return false; // not supported by X + case Mouse::XButton2: return false; // not supported by X + } + + NazaraError("Mouse button not supported."); return false; } - uint16_t buttons = pointer->mask; - - switch (button) + void EventImpl::SetMousePosition(int x, int y) { - case NzMouse::Left: return buttons & XCB_BUTTON_MASK_1; - case NzMouse::Right: return buttons & XCB_BUTTON_MASK_3; - case NzMouse::Middle: return buttons & XCB_BUTTON_MASK_2; - case NzMouse::XButton1: return false; // not supported by X - case NzMouse::XButton2: return false; // not supported by X - } + ScopedXCBConnection connection; - NazaraError("Mouse button not supported."); - return false; -} + xcb_window_t root = X11::XCBDefaultRootWindow(connection); -void NzEventImpl::SetMousePosition(int x, int y) -{ - NzScopedXCBConnection connection; - - xcb_window_t root = X11::XCBDefaultRootWindow(connection); - - if (!X11::CheckCookie( - connection, - xcb_warp_pointer( - connection, - None, // Source window - root, // Destination window - 0, 0, // Source position - 0, 0, // Source size - x, y // Destination position - )) - ) - NazaraError("Failed to set mouse position"); - - xcb_flush(connection); -} - -void NzEventImpl::SetMousePosition(int x, int y, const NzWindow& relativeTo) -{ - NzScopedXCBConnection connection; - - NzWindowHandle handle = relativeTo.GetHandle(); - if (handle) - { if (!X11::CheckCookie( connection, xcb_warp_pointer( connection, - None, // Source window - handle, // Destination window - 0, 0, // Source position - 0, 0, // Source size - x, y // Destination position + None, // Source window + root, // Destination window + 0, 0, // Source position + 0, 0, // Source size + x, y // Destination position )) ) - NazaraError("Failed to set mouse position relative to window"); + NazaraError("Failed to set mouse position"); xcb_flush(connection); } - else - NazaraError("No window handle"); + + void EventImpl::SetMousePosition(int x, int y, const Window& relativeTo) + { + ScopedXCBConnection connection; + + WindowHandle handle = relativeTo.GetHandle(); + if (handle) + { + if (!X11::CheckCookie( + connection, + xcb_warp_pointer( + connection, + None, // Source window + handle, // Destination window + 0, 0, // Source position + 0, 0, // Source size + x, y // Destination position + )) + ) + NazaraError("Failed to set mouse position relative to window"); + + xcb_flush(connection); + } + else + NazaraError("No window handle"); + } } diff --git a/src/Nazara/Utility/X11/InputImpl.hpp b/src/Nazara/Utility/X11/InputImpl.hpp index e99726740..608585b1e 100644 --- a/src/Nazara/Utility/X11/InputImpl.hpp +++ b/src/Nazara/Utility/X11/InputImpl.hpp @@ -7,21 +7,25 @@ #ifndef NAZARA_INPUTIMPL_HPP #define NAZARA_INPUTIMPL_HPP +#include #include #include #include #include -class NzEventImpl +namespace Nz { - public: - static NzString GetKeyName(NzKeyboard::Key key); - static NzVector2i GetMousePosition(); - static NzVector2i GetMousePosition(const NzWindow& relativeTo); - static bool IsKeyPressed(NzKeyboard::Key key); - static bool IsMouseButtonPressed(NzMouse::Button button); - static void SetMousePosition(int x, int y); - static void SetMousePosition(int x, int y, const NzWindow& relativeTo); -}; + class EventImpl + { + public: + static String GetKeyName(Keyboard::Key key); + static Vector2i GetMousePosition(); + static Vector2i GetMousePosition(const Window& relativeTo); + static bool IsKeyPressed(Keyboard::Key key); + static bool IsMouseButtonPressed(Mouse::Button button); + static void SetMousePosition(int x, int y); + static void SetMousePosition(int x, int y, const Window& relativeTo); + }; +} #endif // NAZARA_INPUTIMPL_HPP diff --git a/src/Nazara/Utility/X11/ScopedXCB.cpp b/src/Nazara/Utility/X11/ScopedXCB.cpp index 296213e79..49bd76b26 100644 --- a/src/Nazara/Utility/X11/ScopedXCB.cpp +++ b/src/Nazara/Utility/X11/ScopedXCB.cpp @@ -8,189 +8,192 @@ #include #include -/*********************************************** - NzScopedXCBConnection -***********************************************/ - -NzScopedXCBConnection::NzScopedXCBConnection() : -m_connection(nullptr) +namespace Nz { - m_connection = X11::OpenConnection(); -} + /*********************************************** + ScopedXCBConnection + ***********************************************/ -NzScopedXCBConnection::~NzScopedXCBConnection() -{ - X11::CloseConnection(m_connection); -} + ScopedXCBConnection::ScopedXCBConnection() : + m_connection(nullptr) + { + m_connection = X11::OpenConnection(); + } -NzScopedXCBConnection::operator xcb_connection_t*() const -{ - return m_connection; -} + ScopedXCBConnection::~ScopedXCBConnection() + { + X11::CloseConnection(m_connection); + } -/*********************************************** - NzScopedXCBEWMHConnection -***********************************************/ + ScopedXCBConnection::operator xcb_connection_t*() const + { + return m_connection; + } -NzScopedXCBEWMHConnection::NzScopedXCBEWMHConnection(xcb_connection_t* connection) : -m_ewmhConnection(nullptr) -{ - m_ewmhConnection = X11::OpenEWMHConnection(connection); -} + /*********************************************** + ScopedXCBEWMHConnection + ***********************************************/ -NzScopedXCBEWMHConnection::~NzScopedXCBEWMHConnection() -{ - X11::CloseEWMHConnection(m_ewmhConnection); -} + ScopedXCBEWMHConnection::ScopedXCBEWMHConnection(xcb_connection_t* connection) : + m_ewmhConnection(nullptr) + { + m_ewmhConnection = X11::OpenEWMHConnection(connection); + } -xcb_ewmh_connection_t* NzScopedXCBEWMHConnection::operator ->() const -{ - return m_ewmhConnection; -} + ScopedXCBEWMHConnection::~ScopedXCBEWMHConnection() + { + X11::CloseEWMHConnection(m_ewmhConnection); + } -NzScopedXCBEWMHConnection::operator xcb_ewmh_connection_t*() const -{ - return m_ewmhConnection; -} + xcb_ewmh_connection_t* ScopedXCBEWMHConnection::operator ->() const + { + return m_ewmhConnection; + } -/*********************************************** - NzXCBGContext -***********************************************/ + ScopedXCBEWMHConnection::operator xcb_ewmh_connection_t*() const + { + return m_ewmhConnection; + } -NzXCBGContext::NzXCBGContext(xcb_connection_t* connection) : -m_connection(connection), -m_gcontext(XCB_NONE) -{ - NazaraAssert(connection, "Connection must have been established"); -} + /*********************************************** + XCBGContext + ***********************************************/ -NzXCBGContext::~NzXCBGContext() -{ - Destroy(); -} + XCBGContext::XCBGContext(xcb_connection_t* connection) : + m_connection(connection), + m_gcontext(XCB_NONE) + { + NazaraAssert(connection, "Connection must have been established"); + } -bool NzXCBGContext::Create(xcb_drawable_t drawable, uint32_t value_mask, const uint32_t* value_list) -{ - NazaraAssert(m_gcontext == XCB_NONE, "Context must have been destroyed before or just created"); + XCBGContext::~XCBGContext() + { + Destroy(); + } - m_gcontext = xcb_generate_id(m_connection); + bool XCBGContext::Create(xcb_drawable_t drawable, uint32_t value_mask, const uint32_t* value_list) + { + NazaraAssert(m_gcontext == XCB_NONE, "Context must have been destroyed before or just created"); - return X11::CheckCookie( - m_connection, - xcb_create_gc( + m_gcontext = xcb_generate_id(m_connection); + + return X11::CheckCookie( + m_connection, + xcb_create_gc( + m_connection, + m_gcontext, + drawable, + value_mask, + value_list + )); + } + + void XCBGContext::Destroy() + { + if (m_gcontext == XCB_NONE) + return; + + if (!X11::CheckCookie( + m_connection, + xcb_free_gc( + m_connection, + m_gcontext + )) + ) + NazaraError("Failed to free gcontext"); + + m_gcontext = XCB_NONE; + } + + XCBGContext::operator xcb_gcontext_t() const + { + return m_gcontext; + } + + /*********************************************** + XCBPixmap + ***********************************************/ + + XCBPixmap::XCBPixmap() : + m_connection(nullptr), + m_pixmap(XCB_NONE) + { + } + + XCBPixmap::XCBPixmap(xcb_connection_t* connection) : + m_connection(connection), + m_pixmap(XCB_NONE) + { + } + + XCBPixmap::~XCBPixmap() + { + Destroy(); + } + + void XCBPixmap::Connect(xcb_connection_t* connection) + { + NazaraAssert(connection && !m_connection, "Connection must be established"); + + m_connection = connection; + } + + bool XCBPixmap::Create(uint8_t depth, xcb_drawable_t drawable, uint16_t width, uint16_t height) + { + NazaraAssert(m_pixmap == XCB_NONE, "Pixmap must have been destroyed before or just created"); + + m_pixmap = xcb_generate_id(m_connection); + + return X11::CheckCookie( + m_connection, + xcb_create_pixmap( + m_connection, + depth, + m_pixmap, + drawable, + width, + height + )); + } + + bool XCBPixmap::CreatePixmapFromBitmapData(xcb_drawable_t drawable, uint8_t* data, uint32_t width, uint32_t height, uint32_t depth, uint32_t fg, uint32_t bg, xcb_gcontext_t* gcp) + { + NazaraAssert(m_pixmap == XCB_NONE, "Pixmap must have been destroyed before or just created"); + + m_pixmap = xcb_create_pixmap_from_bitmap_data( m_connection, - m_gcontext, - drawable, - value_mask, - value_list - )); -} - -void NzXCBGContext::Destroy() -{ - if (m_gcontext == XCB_NONE) - return; - - if (!X11::CheckCookie( - m_connection, - xcb_free_gc( - m_connection, - m_gcontext - )) - ) - NazaraError("Failed to free gcontext"); - - m_gcontext = XCB_NONE; -} - -NzXCBGContext::operator xcb_gcontext_t() const -{ - return m_gcontext; -} - -/*********************************************** - NzXCBPixmap -***********************************************/ - -NzXCBPixmap::NzXCBPixmap() : -m_connection(nullptr), -m_pixmap(XCB_NONE) -{ -} - -NzXCBPixmap::NzXCBPixmap(xcb_connection_t* connection) : -m_connection(connection), -m_pixmap(XCB_NONE) -{ -} - -NzXCBPixmap::~NzXCBPixmap() -{ - Destroy(); -} - -void NzXCBPixmap::Connect(xcb_connection_t* connection) -{ - NazaraAssert(connection && !m_connection, "Connection must be established"); - - m_connection = connection; -} - -bool NzXCBPixmap::Create(uint8_t depth, xcb_drawable_t drawable, uint16_t width, uint16_t height) -{ - NazaraAssert(m_pixmap == XCB_NONE, "Pixmap must have been destroyed before or just created"); - - m_pixmap = xcb_generate_id(m_connection); - - return X11::CheckCookie( - m_connection, - xcb_create_pixmap( - m_connection, - depth, - m_pixmap, drawable, + data, width, - height - )); -} + height, + depth, + fg, + bg, + gcp + ); -bool NzXCBPixmap::CreatePixmapFromBitmapData(xcb_drawable_t drawable, uint8_t* data, uint32_t width, uint32_t height, uint32_t depth, uint32_t fg, uint32_t bg, xcb_gcontext_t* gcp) -{ - NazaraAssert(m_pixmap == XCB_NONE, "Pixmap must have been destroyed before or just created"); + return m_pixmap != XCB_NONE; + } - m_pixmap = xcb_create_pixmap_from_bitmap_data( - m_connection, - drawable, - data, - width, - height, - depth, - fg, - bg, - gcp - ); + void XCBPixmap::Destroy() + { + if (m_pixmap == XCB_NONE) + return; - return m_pixmap != XCB_NONE; -} - -void NzXCBPixmap::Destroy() -{ - if (m_pixmap == XCB_NONE) - return; - - if (!X11::CheckCookie( - m_connection, - xcb_free_pixmap( + if (!X11::CheckCookie( m_connection, - m_pixmap - )) - ) - NazaraError("Failed to free pixmap"); + xcb_free_pixmap( + m_connection, + m_pixmap + )) + ) + NazaraError("Failed to free pixmap"); - m_pixmap = XCB_NONE; -} + m_pixmap = XCB_NONE; + } -NzXCBPixmap::operator xcb_pixmap_t() const -{ - return m_pixmap; + XCBPixmap::operator xcb_pixmap_t() const + { + return m_pixmap; + } } diff --git a/src/Nazara/Utility/X11/ScopedXCB.hpp b/src/Nazara/Utility/X11/ScopedXCB.hpp index 35ef9009b..452379bc4 100644 --- a/src/Nazara/Utility/X11/ScopedXCB.hpp +++ b/src/Nazara/Utility/X11/ScopedXCB.hpp @@ -7,88 +7,93 @@ #ifndef NAZARA_SCOPEDXCB_HPP #define NAZARA_SCOPEDXCB_HPP +#include +#include #include -class NzScopedXCBConnection +namespace Nz { - public: - NzScopedXCBConnection(); - ~NzScopedXCBConnection(); + class ScopedXCBConnection + { + public: + ScopedXCBConnection(); + ~ScopedXCBConnection(); - operator xcb_connection_t*() const; + operator xcb_connection_t*() const; - private: - xcb_connection_t* m_connection; -}; + private: + xcb_connection_t* m_connection; + }; -class NzScopedXCBEWMHConnection -{ - public: - NzScopedXCBEWMHConnection(xcb_connection_t* connection); - ~NzScopedXCBEWMHConnection(); + class ScopedXCBEWMHConnection + { + public: + ScopedXCBEWMHConnection(xcb_connection_t* connection); + ~ScopedXCBEWMHConnection(); - xcb_ewmh_connection_t* operator ->() const; + xcb_ewmh_connection_t* operator ->() const; - operator xcb_ewmh_connection_t*() const; + operator xcb_ewmh_connection_t*() const; - private: - xcb_ewmh_connection_t* m_ewmhConnection; -}; + private: + xcb_ewmh_connection_t* m_ewmhConnection; + }; -template -class NzScopedXCB -{ - public: - NzScopedXCB(T* pointer); - ~NzScopedXCB(); + template + class ScopedXCB + { + public: + ScopedXCB(T* pointer); + ~ScopedXCB(); - T* operator ->() const; - T** operator &(); + T* operator ->() const; + T** operator &(); - operator bool() const; + operator bool() const; - T* get() const; + T* get() const; - private: - T* m_pointer; -}; + private: + T* m_pointer; + }; -class NzXCBGContext -{ - public: - NzXCBGContext(xcb_connection_t* connection); - ~NzXCBGContext(); + class XCBGContext + { + public: + XCBGContext(xcb_connection_t* connection); + ~XCBGContext(); - bool Create(xcb_drawable_t drawable, uint32_t value_mask, const uint32_t* value_list); + bool Create(xcb_drawable_t drawable, uint32_t value_mask, const uint32_t* value_list); - void Destroy(); + void Destroy(); - operator xcb_gcontext_t() const; + operator xcb_gcontext_t() const; - private: - xcb_connection_t* m_connection; - xcb_gcontext_t m_gcontext; -}; + private: + xcb_connection_t* m_connection; + xcb_gcontext_t m_gcontext; + }; -class NzXCBPixmap -{ - public: - NzXCBPixmap(); - NzXCBPixmap(xcb_connection_t* connection); - ~NzXCBPixmap(); + class XCBPixmap + { + public: + XCBPixmap(); + XCBPixmap(xcb_connection_t* connection); + ~XCBPixmap(); - void Connect(xcb_connection_t* connection); - bool Create(uint8_t depth, xcb_drawable_t drawable, uint16_t width, uint16_t height); - bool CreatePixmapFromBitmapData(xcb_drawable_t drawable, uint8_t* data, uint32_t width, uint32_t height, uint32_t depth, uint32_t fg, uint32_t bg, xcb_gcontext_t* gcp); + void Connect(xcb_connection_t* connection); + bool Create(uint8_t depth, xcb_drawable_t drawable, uint16_t width, uint16_t height); + bool CreatePixmapFromBitmapData(xcb_drawable_t drawable, uint8_t* data, uint32_t width, uint32_t height, uint32_t depth, uint32_t fg, uint32_t bg, xcb_gcontext_t* gcp); - void Destroy(); + void Destroy(); - operator xcb_pixmap_t() const; + operator xcb_pixmap_t() const; - private: - xcb_connection_t* m_connection; - xcb_pixmap_t m_pixmap; -}; + private: + xcb_connection_t* m_connection; + xcb_pixmap_t m_pixmap; + }; +} #include diff --git a/src/Nazara/Utility/X11/VideoModeImpl.cpp b/src/Nazara/Utility/X11/VideoModeImpl.cpp index dcdec7f97..e0b9a5ce7 100644 --- a/src/Nazara/Utility/X11/VideoModeImpl.cpp +++ b/src/Nazara/Utility/X11/VideoModeImpl.cpp @@ -10,156 +10,159 @@ #include #include -NzVideoMode NzVideoModeImpl::GetDesktopMode() +namespace Nz { - NzVideoMode desktopMode; - - NzScopedXCBConnection connection; - - // Retrieve the default screen - xcb_screen_t* screen = X11::XCBDefaultScreen(connection); - - NzScopedXCB error(nullptr); - - // Check if the RandR extension is present - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) + VideoMode VideoModeImpl::GetDesktopMode() { - // Randr extension is not supported: we cannot get the video modes - NazaraError("Failed to use the RandR extension while trying to get the desktop video mode"); - return desktopMode; - } + VideoMode desktopMode; - // Load RandR and check its version - NzScopedXCB randrVersion(xcb_randr_query_version_reply( - connection, - xcb_randr_query_version( - connection, - 1, - 1 - ), - &error - )); + ScopedXCBConnection connection; - if (error) - { - NazaraError("Failed to load the RandR extension while trying to get the desktop video mode"); - return desktopMode; - } + // Retrieve the default screen + xcb_screen_t* screen = X11::XCBDefaultScreen(connection); - // Get the current configuration - NzScopedXCB config(xcb_randr_get_screen_info_reply( - connection, - xcb_randr_get_screen_info( - connection, - screen->root - ), - &error - )); + ScopedXCB error(nullptr); - if (error) - { - // Failed to get the screen configuration - NazaraError("Failed to retrieve the screen configuration while trying to get the desktop video mode"); - return desktopMode; - } + // Check if the RandR extension is present + const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); - // Get the current video mode - xcb_randr_mode_t currentMode = config->sizeID; - - // Get the available screen sizes - int nbSizes = xcb_randr_get_screen_info_sizes_length(config.get()); - xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); - if (sizes && (nbSizes > 0)) - { - desktopMode = NzVideoMode(sizes[currentMode].width, sizes[currentMode].height, screen->root_depth); - - if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) - std::swap(desktopMode.width, desktopMode.height); - } - else - { - NazaraError("Failed to retrieve any screen sizes while trying to get the desktop video mode"); - } - - return desktopMode; -} - -void NzVideoModeImpl::GetFullscreenModes(std::vector& modes) -{ - NzScopedXCBConnection connection; - - // Retrieve the default screen - xcb_screen_t* screen = X11::XCBDefaultScreen(connection); - - NzScopedXCB error(nullptr); - - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) - { - // Randr extension is not supported: we cannot get the video modes - NazaraError("Failed to use the RandR extension while trying to get the supported video modes"); - return; - } - - // Load RandR and check its version - NzScopedXCB randrVersion(xcb_randr_query_version_reply( - connection, - xcb_randr_query_version( - connection, - 1, - 1 - ), - &error - )); - - if (error) - { - NazaraError("Failed to load the RandR extension while trying to get the supported video modes"); - return; - } - - // Get the current configuration - NzScopedXCB config(xcb_randr_get_screen_info_reply( - connection, - xcb_randr_get_screen_info( - connection, - screen->root - ), - &error - )); - - if (error) - { - // Failed to get the screen configuration - NazaraError("Failed to retrieve the screen configuration while trying to get the supported video modes"); - return; - } - - // Get the available screen sizes - xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); - if (sizes && (config->nSizes > 0)) - { - // Get the list of supported depths - xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(screen); - // Combine depths and sizes to fill the array of supported modes - for (; iter.rem; xcb_depth_next(&iter)) + if (!randrExt || !randrExt->present) { - for (int j = 0; j < config->nSizes; ++j) + // Randr extension is not supported: we cannot get the video modes + NazaraError("Failed to use the RandR extension while trying to get the desktop video mode"); + return desktopMode; + } + + // Load RandR and check its version + ScopedXCB randrVersion(xcb_randr_query_version_reply( + connection, + xcb_randr_query_version( + connection, + 1, + 1 + ), + &error + )); + + if (error) + { + NazaraError("Failed to load the RandR extension while trying to get the desktop video mode"); + return desktopMode; + } + + // Get the current configuration + ScopedXCB config(xcb_randr_get_screen_info_reply( + connection, + xcb_randr_get_screen_info( + connection, + screen->root + ), + &error + )); + + if (error) + { + // Failed to get the screen configuration + NazaraError("Failed to retrieve the screen configuration while trying to get the desktop video mode"); + return desktopMode; + } + + // Get the current video mode + xcb_randr_mode_t currentMode = config->sizeID; + + // Get the available screen sizes + int nbSizes = xcb_randr_get_screen_info_sizes_length(config.get()); + xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); + if (sizes && (nbSizes > 0)) + { + desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, screen->root_depth); + + if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || + config->rotation == XCB_RANDR_ROTATION_ROTATE_270) + std::swap(desktopMode.width, desktopMode.height); + } + else + { + NazaraError("Failed to retrieve any screen sizes while trying to get the desktop video mode"); + } + + return desktopMode; + } + + void VideoModeImpl::GetFullscreenModes(std::vector& modes) + { + ScopedXCBConnection connection; + + // Retrieve the default screen + xcb_screen_t* screen = X11::XCBDefaultScreen(connection); + + ScopedXCB error(nullptr); + + const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); + + if (!randrExt || !randrExt->present) + { + // Randr extension is not supported: we cannot get the video modes + NazaraError("Failed to use the RandR extension while trying to get the supported video modes"); + return; + } + + // Load RandR and check its version + ScopedXCB randrVersion(xcb_randr_query_version_reply( + connection, + xcb_randr_query_version( + connection, + 1, + 1 + ), + &error + )); + + if (error) + { + NazaraError("Failed to load the RandR extension while trying to get the supported video modes"); + return; + } + + // Get the current configuration + ScopedXCB config(xcb_randr_get_screen_info_reply( + connection, + xcb_randr_get_screen_info( + connection, + screen->root + ), + &error + )); + + if (error) + { + // Failed to get the screen configuration + NazaraError("Failed to retrieve the screen configuration while trying to get the supported video modes"); + return; + } + + // Get the available screen sizes + xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); + if (sizes && (config->nSizes > 0)) + { + // Get the list of supported depths + xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(screen); + // Combine depths and sizes to fill the array of supported modes + for (; iter.rem; xcb_depth_next(&iter)) { - // Convert to VideoMode - NzVideoMode mode(sizes[j].width, sizes[j].height, iter.data->depth); + for (int j = 0; j < config->nSizes; ++j) + { + // Convert to VideoMode + VideoMode mode(sizes[j].width, sizes[j].height, iter.data->depth); - if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) - std::swap(mode.width, mode.height); + if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || + config->rotation == XCB_RANDR_ROTATION_ROTATE_270) + std::swap(mode.width, mode.height); - // Add it only if it is not already in the array - if (std::find(modes.begin(), modes.end(), mode) == modes.end()) - modes.push_back(mode); + // Add it only if it is not already in the array + if (std::find(modes.begin(), modes.end(), mode) == modes.end()) + modes.push_back(mode); + } } } } diff --git a/src/Nazara/Utility/X11/VideoModeImpl.hpp b/src/Nazara/Utility/X11/VideoModeImpl.hpp index 3a53f5e94..2e63e8a09 100644 --- a/src/Nazara/Utility/X11/VideoModeImpl.hpp +++ b/src/Nazara/Utility/X11/VideoModeImpl.hpp @@ -7,13 +7,17 @@ #ifndef NAZARA_VIDEOMODEIMPL_HPP #define NAZARA_VIDEOMODEIMPL_HPP +#include #include -class NzVideoModeImpl +namespace Nz { - public: - static NzVideoMode GetDesktopMode(); - static void GetFullscreenModes(std::vector& modes); -}; + class VideoModeImpl + { + public: + static VideoMode GetDesktopMode(); + static void GetFullscreenModes(std::vector& modes); + }; +} #endif // NNAZARA_VIDEOMODEIMPL_HPP diff --git a/src/Nazara/Utility/X11/WindowImpl.cpp b/src/Nazara/Utility/X11/WindowImpl.cpp index 4087ba58d..ecb8f1cc4 100644 --- a/src/Nazara/Utility/X11/WindowImpl.cpp +++ b/src/Nazara/Utility/X11/WindowImpl.cpp @@ -23,1555 +23,1564 @@ #include /* - Icon working sometimes - EnableKeyRepeat (Working but is it the right behaviour ?) - Fullscreen (No alt + tab) - Smooth scroll (???) - Thread (Not tested a lot) - Event listener // ? - Cleanup // Done ? + Things to do left: + + Icon working sometimes (No idea) + EnableKeyRepeat (Working but is it the right behaviour ?) + Fullscreen (No alt + tab) + Smooth scroll (No equivalent for X11) + Threaded window (Not tested a lot) + Event listener (Not tested) + Cleanup + IsVisible (Not working as expected) + SetStayOnTop (Equivalent for X11 ?) + Opengl Context (glXCreateContextAttribs should be loaded like in window and the version for the context should be the one of NzContextParameters) + */ -namespace +namespace Nz { - NzWindowImpl* fullscreenWindow = nullptr; - - const uint32_t eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS | - XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | - XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS | - XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | - XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW; - - xcb_cursor_t hiddenCursor = 0; - - xcb_connection_t* connection = nullptr; - - void CreateHiddenCursor() + namespace { - NzXCBPixmap cursorPixmap(connection); + Nz::WindowImpl* fullscreenWindow = nullptr; - xcb_window_t window = X11::XCBDefaultRootWindow(connection); + const uint32_t eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS | + XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | + XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS | + XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW; - if (!cursorPixmap.Create( - 1, - window, - 1, - 1 - )) + xcb_cursor_t hiddenCursor = 0; + + xcb_connection_t* connection = nullptr; + + void CreateHiddenCursor() { - NazaraError("Failed to create pixmap for hidden cursor"); - return; - } + XCBPixmap cursorPixmap(connection); - hiddenCursor = xcb_generate_id(connection); + xcb_window_t window = X11::XCBDefaultRootWindow(connection); - // Create the cursor, using the pixmap as both the shape and the mask of the cursor - if (!X11::CheckCookie( - connection, - xcb_create_cursor( - connection, - hiddenCursor, - cursorPixmap, - cursorPixmap, - 0, 0, 0, // Foreground RGB color - 0, 0, 0, // Background RGB color - 0, // X - 0 // Y - )) - ) - NazaraError("Failed to create hidden cursor"); - } -} + if (!cursorPixmap.Create( + 1, + window, + 1, + 1 + )) + { + NazaraError("Failed to create pixmap for hidden cursor"); + return; + } -NzWindowImpl::NzWindowImpl(NzWindow* parent) : -m_window(0), -m_style(0), -m_parent(parent), -m_smoothScrolling(false), -m_scrolling(0), -m_mousePos(0, 0), -m_keyRepeat(true) -{ - std::memset(&m_size_hints, 0, sizeof(m_size_hints)); -} - -NzWindowImpl::~NzWindowImpl() -{ - // Cleanup graphical resources - CleanUp(); - - // We clean up the event queue - UpdateEventQueue(nullptr); - UpdateEventQueue(nullptr); -} - -bool NzWindowImpl::Create(const NzVideoMode& mode, const NzString& title, nzUInt32 style) -{ - bool fullscreen = (style & nzWindowStyle_Fullscreen) != 0; - m_eventListener = true; - m_ownsWindow = true; - m_style = style; - - std::memset(&m_oldVideoMode, 0, sizeof(m_oldVideoMode)); - - m_screen = X11::XCBDefaultScreen(connection); - - // Compute position and size - int left = fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2; - int top = fullscreen ? 0 : (m_screen->height_in_pixels - mode.height) / 2; - int width = mode.width; - int height = mode.height; - - // Define the window attributes - xcb_colormap_t colormap = xcb_generate_id(connection); - xcb_create_colormap(connection, XCB_COLORMAP_ALLOC_NONE, colormap, m_screen->root, m_screen->root_visual); - const uint32_t value_list[] = { fullscreen, eventMask, colormap }; - - NzCallOnExit onExit([&](){ - if (!X11::CheckCookie( - connection, - xcb_free_colormap( - connection, - colormap - )) - ) - NazaraError("Failed to free colormap"); - }); - - // Create the window - m_window = xcb_generate_id(connection); - - if (!X11::CheckCookie( - connection, - xcb_create_window_checked( - connection, - XCB_COPY_FROM_PARENT, - m_window, - m_screen->root, - left, top, - width, height, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - m_screen->root_visual, - XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP, - value_list - ))) - { - NazaraError("Failed to create window"); - return false; - } - - // Flush the commands queue - xcb_flush(connection); - - // We get default normal hints for the new window - NzScopedXCB error(nullptr); - xcb_icccm_get_wm_normal_hints_reply( - connection, - xcb_icccm_get_wm_normal_hints( - connection, - m_window), - &m_size_hints, - &error - ); - if (error) - NazaraError("Failed to get size hints"); - - // And we modify the size and the position. - xcb_icccm_size_hints_set_position(&m_size_hints, false, left, top); - xcb_icccm_size_hints_set_size(&m_size_hints, false, width, height); - if (!UpdateNormalHints()) - NazaraError("Failed to set window configuration"); - - // Do some common initializations - CommonInitialize(); - - if (!(m_style & nzWindowStyle_Fullscreen)) - SetMotifHints(); - - // Flush the commands queue - xcb_flush(connection); - - // Set the window's name - SetTitle(title); - - #if NAZARA_UTILITY_THREADED_WINDOW - NzMutex mutex; - NzConditionVariable condition; - m_threadActive = true; - - // We wait that thread is well launched - mutex.Lock(); - m_thread = NzThread(WindowThread, this, &mutex, &condition); - condition.Wait(&mutex); - mutex.Unlock(); - #endif - - // Set fullscreen video mode and switch to fullscreen if necessary - if (fullscreen) - { - SetPosition(0, 0); - SetVideoMode(mode); - SwitchToFullscreen(); - } - - return true; -} - -bool NzWindowImpl::Create(NzWindowHandle handle) -{ - std::memset(&m_oldVideoMode, 0, sizeof(m_oldVideoMode)); - - m_screen = X11::XCBDefaultScreen(connection); - - if (!handle) - { - NazaraError("Invalid handle"); - return false; - } - - // Save the window handle - m_window = handle; - - m_ownsWindow = false; - m_eventListener = false; - - NzScopedXCB error(nullptr); - - // We try to get informations from the shared window. - xcb_icccm_get_wm_normal_hints_reply( - connection, - xcb_icccm_get_wm_normal_hints( - connection, - m_window), - &m_size_hints, - &error - ); - - if (error) - { - NazaraError("Failed to obtain sizes and positions"); - return false; - } - - // Do some common initializations - CommonInitialize(); - - // Flush the commands queue - xcb_flush(connection); - - return true; -} - -void NzWindowImpl::Destroy() -{ - if (m_ownsWindow) - { - #if NAZARA_UTILITY_THREADED_WINDOW - if (m_thread.IsJoinable()) - { - m_threadActive = false; - m_thread.Join(); - } - #else - // Destroy the window - if (m_window && m_ownsWindow) - { - // Unhide the mouse cursor (in case it was hidden) - SetCursor(nzWindowCursor_Default); + hiddenCursor = xcb_generate_id(connection); + // Create the cursor, using the pixmap as both the shape and the mask of the cursor if (!X11::CheckCookie( connection, - xcb_destroy_window( + xcb_create_cursor( connection, - m_window + hiddenCursor, + cursorPixmap, + cursorPixmap, + 0, 0, 0, // Foreground RGB color + 0, 0, 0, // Background RGB color + 0, // X + 0 // Y )) ) - NazaraError("Failed to destroy window"); - - xcb_flush(connection); + NazaraError("Failed to create hidden cursor"); } - #endif - } - else - SetEventListener(false); -} - -void NzWindowImpl::EnableKeyRepeat(bool enable) -{ - m_keyRepeat = enable; -} - -void NzWindowImpl::EnableSmoothScrolling(bool enable) -{ - m_smoothScrolling = enable; -} - -NzWindowHandle NzWindowImpl::GetHandle() const -{ - return m_window; -} - -unsigned int NzWindowImpl::GetHeight() const -{ - return m_size_hints.height; -} - -NzVector2i NzWindowImpl::GetPosition() const -{ - return { m_size_hints.x, m_size_hints.y }; -} - -NzVector2ui NzWindowImpl::GetSize() const -{ - return NzVector2ui(m_size_hints.width, m_size_hints.height); -} - -nzUInt32 NzWindowImpl::GetStyle() const -{ - return m_style; -} - -NzString NzWindowImpl::GetTitle() const -{ - NzScopedXCBEWMHConnection ewmhConnection(connection); - - NzScopedXCB error(nullptr); - - xcb_ewmh_get_utf8_strings_reply_t data; - xcb_ewmh_get_wm_name_reply(ewmhConnection, - xcb_ewmh_get_wm_name(ewmhConnection, m_window), &data, &error); - - if (error) - NazaraError("Failed to get window's title"); - - NzString tmp(data.strings, data.strings_len); - - xcb_ewmh_get_utf8_strings_reply_wipe(&data); - - return tmp; -} - -unsigned int NzWindowImpl::GetWidth() const -{ - return m_size_hints.width; -} - -bool NzWindowImpl::HasFocus() const -{ - NzScopedXCB error(nullptr); - - NzScopedXCB reply(xcb_get_input_focus_reply( - connection, - xcb_get_input_focus_unchecked( - connection - ), - &error - )); - - if (error) - NazaraError("Failed to check if window has focus"); - - return (reply->focus == m_window); -} - -void NzWindowImpl::IgnoreNextMouseEvent(int mouseX, int mouseY) -{ - // Petite astuce ... - m_mousePos.x = mouseX; - m_mousePos.y = mouseY; -} - -bool NzWindowImpl::IsMinimized() const -{ - NzScopedXCBEWMHConnection ewmhConnection(connection); - - NzScopedXCB error(nullptr); - bool isMinimized = false; - - xcb_ewmh_get_atoms_reply_t atomReply; - if (xcb_ewmh_get_wm_state_reply(ewmhConnection, - xcb_ewmh_get_wm_state(ewmhConnection, m_window), &atomReply, &error) == 1) - { - for (unsigned int i = 0; i < atomReply.atoms_len; i++) - if (atomReply.atoms[i] == ewmhConnection->_NET_WM_STATE_HIDDEN) - isMinimized = true; - - xcb_ewmh_get_atoms_reply_wipe(&atomReply); } - if (error) - NazaraError("Failed to determine if window is minimized"); - - return isMinimized; -} - -bool NzWindowImpl::IsVisible() const -{ - return !IsMinimized(); // Visibility event ? -} - -void NzWindowImpl::ProcessEvents(bool block) -{ - if (m_ownsWindow) + WindowImpl::WindowImpl(Window* parent) : + m_window(0), + m_style(0), + m_parent(parent), + m_smoothScrolling(false), + m_scrolling(0), + m_mousePos(0, 0), + m_keyRepeat(true) { - xcb_generic_event_t* event = nullptr; + std::memset(&m_size_hints, 0, sizeof(m_size_hints)); + } - if (block) + WindowImpl::~WindowImpl() + { + // Cleanup graphical resources + CleanUp(); + + // We clean up the event queue + UpdateEventQueue(nullptr); + UpdateEventQueue(nullptr); + } + + bool WindowImpl::Create(const VideoMode& mode, const String& title, UInt32 style) + { + bool fullscreen = (style & Nz::WindowStyle_Fullscreen) != 0; + m_eventListener = true; + m_ownsWindow = true; + m_style = style; + + std::memset(&m_oldVideoMode, 0, sizeof(m_oldVideoMode)); + + m_screen = X11::XCBDefaultScreen(connection); + + // Compute position and size + int left = fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2; + int top = fullscreen ? 0 : (m_screen->height_in_pixels - mode.height) / 2; + int width = mode.width; + int height = mode.height; + + // Define the window attributes + xcb_colormap_t colormap = xcb_generate_id(connection); + xcb_create_colormap(connection, XCB_COLORMAP_ALLOC_NONE, colormap, m_screen->root, m_screen->root_visual); + const uint32_t value_list[] = { fullscreen, eventMask, colormap }; + + CallOnExit onExit([&](){ + if (!X11::CheckCookie( + connection, + xcb_free_colormap( + connection, + colormap + )) + ) + NazaraError("Failed to free colormap"); + }); + + // Create the window + m_window = xcb_generate_id(connection); + + if (!X11::CheckCookie( + connection, + xcb_create_window_checked( + connection, + XCB_COPY_FROM_PARENT, + m_window, + m_screen->root, + left, top, + width, height, + 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + m_screen->root_visual, + XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP, + value_list + ))) { - event = xcb_wait_for_event(connection); - if (event) + NazaraError("Failed to create window"); + return false; + } + + // Flush the commands queue + xcb_flush(connection); + + // We get default normal hints for the new window + ScopedXCB error(nullptr); + xcb_icccm_get_wm_normal_hints_reply( + connection, + xcb_icccm_get_wm_normal_hints( + connection, + m_window), + &m_size_hints, + &error + ); + if (error) + NazaraError("Failed to get size hints"); + + // And we modify the size and the position. + xcb_icccm_size_hints_set_position(&m_size_hints, false, left, top); + xcb_icccm_size_hints_set_size(&m_size_hints, false, width, height); + if (!UpdateNormalHints()) + NazaraError("Failed to set window configuration"); + + // Do some common initializations + CommonInitialize(); + + if (!(m_style & Nz::WindowStyle_Fullscreen)) + SetMotifHints(); + + // Flush the commands queue + xcb_flush(connection); + + // Set the window's name + SetTitle(title); + + #if NAZARA_UTILITY_THREADED_WINDOW + Mutex mutex; + ConditionVariable condition; + m_threadActive = true; + + // We wait that thread is well launched + mutex.Lock(); + m_thread = Thread(WindowThread, this, &mutex, &condition); + condition.Wait(&mutex); + mutex.Unlock(); + #endif + + // Set fullscreen video mode and switch to fullscreen if necessary + if (fullscreen) + { + SetPosition(0, 0); + SetVideoMode(mode); + SwitchToFullscreen(); + } + + return true; + } + + bool WindowImpl::Create(WindowHandle handle) + { + std::memset(&m_oldVideoMode, 0, sizeof(m_oldVideoMode)); + + m_screen = X11::XCBDefaultScreen(connection); + + if (!handle) + { + NazaraError("Invalid handle"); + return false; + } + + // Save the window handle + m_window = handle; + + m_ownsWindow = false; + m_eventListener = false; + + ScopedXCB error(nullptr); + + // We try to get informations from the shared window. + xcb_icccm_get_wm_normal_hints_reply( + connection, + xcb_icccm_get_wm_normal_hints( + connection, + m_window), + &m_size_hints, + &error + ); + + if (error) + { + NazaraError("Failed to obtain sizes and positions"); + return false; + } + + // Do some common initializations + CommonInitialize(); + + // Flush the commands queue + xcb_flush(connection); + + return true; + } + + void WindowImpl::Destroy() + { + if (m_ownsWindow) + { + #if NAZARA_UTILITY_THREADED_WINDOW + if (m_thread.IsJoinable()) { - UpdateEventQueue(event); - ProcessEvent(event); + m_threadActive = false; + m_thread.Join(); } + #else + // Destroy the window + if (m_window && m_ownsWindow) + { + // Unhide the mouse cursor (in case it was hidden) + SetCursor(Nz::WindowCursor_Default); + + if (!X11::CheckCookie( + connection, + xcb_destroy_window( + connection, + m_window + )) + ) + NazaraError("Failed to destroy window"); + + xcb_flush(connection); + } + #endif } else - { - event = xcb_poll_for_event(connection); - while (event) - { - UpdateEventQueue(event); - xcb_generic_event_t* tmp = xcb_poll_for_event(connection); - UpdateEventQueue(tmp); - ProcessEvent(event); - if (tmp) - ProcessEvent(tmp); - event = xcb_poll_for_event(connection); - } - } + SetEventListener(false); } -} -void NzWindowImpl::SetCursor(nzWindowCursor windowCursor) -{ - if (windowCursor == nzWindowCursor_None) - SetCursor(hiddenCursor); - else + void WindowImpl::EnableKeyRepeat(bool enable) { - const char* name = ConvertWindowCursorToXName(windowCursor); - - xcb_cursor_context_t* ctx; - if (xcb_cursor_context_new(connection, m_screen, &ctx) >= 0) - { - xcb_cursor_t cursor = xcb_cursor_load_cursor(ctx, name); - SetCursor(cursor); - xcb_free_cursor(connection, cursor); - xcb_cursor_context_free(ctx); - } + m_keyRepeat = enable; } -} -void NzWindowImpl::SetCursor(const NzCursor& cursor) -{ - if (!cursor.IsValid()) + void WindowImpl::EnableSmoothScrolling(bool enable) { - NazaraError("Cursor is not valid"); - return; + m_smoothScrolling = enable; } - SetCursor(cursor.m_impl->GetCursor()); -} - -void NzWindowImpl::SetEventListener(bool listener) -{ - if (m_ownsWindow) - m_eventListener = listener; - else if (listener != m_eventListener) + WindowHandle WindowImpl::GetHandle() const { - if (listener) - { - const uint32_t value_list[] = { eventMask }; - - if (!X11::CheckCookie( - connection, - xcb_change_window_attributes( - connection, - m_window, - XCB_CW_EVENT_MASK, - value_list - )) - ) - NazaraError("Failed to change event for listener"); - - m_eventListener = true; - } - else if (m_eventListener) - { - const uint32_t value_list[] = { XCB_EVENT_MASK_NO_EVENT }; - - if (!X11::CheckCookie( - connection, - xcb_change_window_attributes( - connection, - m_window, - XCB_CW_EVENT_MASK, - value_list - )) - ) - NazaraError("Failed to change event for listener"); - - m_eventListener = false; - } + return m_window; } -} -void NzWindowImpl::SetFocus() -{ - if (!X11::CheckCookie( - connection, - xcb_set_input_focus( + unsigned int WindowImpl::GetHeight() const + { + return m_size_hints.height; + } + + Vector2i WindowImpl::GetPosition() const + { + return { m_size_hints.x, m_size_hints.y }; + } + + Vector2ui WindowImpl::GetSize() const + { + return Vector2ui(m_size_hints.width, m_size_hints.height); + } + + UInt32 WindowImpl::GetStyle() const + { + return m_style; + } + + String WindowImpl::GetTitle() const + { + ScopedXCBEWMHConnection ewmhConnection(connection); + + ScopedXCB error(nullptr); + + xcb_ewmh_get_utf8_strings_reply_t data; + xcb_ewmh_get_wm_name_reply(ewmhConnection, + xcb_ewmh_get_wm_name(ewmhConnection, m_window), &data, &error); + + if (error) + NazaraError("Failed to get window's title"); + + String tmp(data.strings, data.strings_len); + + xcb_ewmh_get_utf8_strings_reply_wipe(&data); + + return tmp; + } + + unsigned int WindowImpl::GetWidth() const + { + return m_size_hints.width; + } + + bool WindowImpl::HasFocus() const + { + ScopedXCB error(nullptr); + + ScopedXCB reply(xcb_get_input_focus_reply( connection, - XCB_INPUT_FOCUS_POINTER_ROOT, - m_window, - XCB_CURRENT_TIME - )) - ) - NazaraError("Failed to set input focus"); - - const uint32_t values[] = { XCB_STACK_MODE_ABOVE }; - - if (!X11::CheckCookie( - connection, - xcb_configure_window( - connection, - m_window, - XCB_CONFIG_WINDOW_STACK_MODE, - values - )) - ) - NazaraError("Failed to set focus"); -} - -void NzWindowImpl::SetIcon(const NzIcon& icon) -{ - if (!icon.IsValid()) - { - NazaraError("Icon is not valid"); - return; - } - - xcb_pixmap_t icon_pixmap = icon.m_impl->GetIcon(); - xcb_pixmap_t mask_pixmap = icon.m_impl->GetMask(); - - NzScopedXCB error(nullptr); - - xcb_icccm_wm_hints_t hints; - std::memset(&hints, 0, sizeof(hints)); - - xcb_icccm_get_wm_hints_reply( - connection, - xcb_icccm_get_wm_hints( - connection, - m_window), - &hints, - &error - ); - - if (error) - NazaraError("Failed to get wm hints"); - - xcb_icccm_wm_hints_set_icon_pixmap(&hints, icon_pixmap); - xcb_icccm_wm_hints_set_icon_mask(&hints, mask_pixmap); - - if (!X11::CheckCookie( - connection, - xcb_icccm_set_wm_hints( - connection, - m_window, - &hints - )) - ) - NazaraError("Failed to set wm hints"); - - xcb_flush(connection); -} - -void NzWindowImpl::SetMaximumSize(int width, int height) -{ - if (width < 0) - width = m_screen->width_in_pixels; - if (height < 0) - height = m_screen->height_in_pixels; - - xcb_icccm_size_hints_set_max_size(&m_size_hints, width, height); - if (!UpdateNormalHints()) - NazaraError("Failed to set maximum size"); - - xcb_flush(connection); -} - -void NzWindowImpl::SetMinimumSize(int width, int height) -{ - xcb_icccm_size_hints_set_min_size(&m_size_hints, width, height); - if (!UpdateNormalHints()) - NazaraError("Failed to set minimum size"); - - xcb_flush(connection); -} - -void NzWindowImpl::SetPosition(int x, int y) -{ - xcb_icccm_size_hints_set_position(&m_size_hints, true, x, y); - if (!UpdateNormalHints()) - NazaraError("Failed to set size hints position"); - - const uint32_t values[] = { static_cast(x), static_cast(y) }; - if (!X11::CheckCookie( - connection, - xcb_configure_window( - connection, - m_window, - XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, - values - )) - ) - NazaraError("Failed to set position"); - - xcb_flush(connection); -} - -void NzWindowImpl::SetSize(unsigned int width, unsigned int height) -{ - xcb_icccm_size_hints_set_size(&m_size_hints, true, width, height); - if (!UpdateNormalHints()) - NazaraError("Failed to set size hints sizes"); - - const uint32_t values[] = { width, height }; - if (!X11::CheckCookie( - connection, - xcb_configure_window( - connection, - m_window, - XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, - values - )) - ) - NazaraError("Failed to set sizes"); - - xcb_flush(connection); -} - -void NzWindowImpl::SetStayOnTop(bool stayOnTop) -{ - NzScopedXCBEWMHConnection ewmhConnection(connection); - - xcb_atom_t onTop; // It is not really working - if (stayOnTop) - onTop = ewmhConnection->_NET_WM_STATE_ABOVE; - else - onTop = ewmhConnection->_NET_WM_STATE_BELOW; - - if (!X11::CheckCookie( - connection, - xcb_ewmh_set_wm_state( - ewmhConnection, - m_window, - 1, - &onTop - )) - ) - NazaraError("Failed to set stay on top"); - - xcb_flush(connection); -} - -void NzWindowImpl::SetTitle(const NzString& title) -{ - NzScopedXCBEWMHConnection ewmhConnection(connection); - - if (!X11::CheckCookie( - connection, - xcb_ewmh_set_wm_name( - ewmhConnection, - m_window, - title.GetSize(), - title.GetConstBuffer() - )) - ) - NazaraError("Failed to set title"); - - xcb_flush(connection); -} - -void NzWindowImpl::SetVisible(bool visible) -{ - if (visible) - { - if (!X11::CheckCookie( - connection, - xcb_map_window( - connection, - m_window - )) - ) - NazaraError("Failed to change window visibility to visible"); - } - else - { - if (!X11::CheckCookie( - connection, - xcb_unmap_window( - connection, - m_window - )) - ) - NazaraError("Failed to change window visibility to invisible"); - } - - xcb_flush(connection); -} - -bool NzWindowImpl::Initialize() -{ - X11::Initialize(); - - connection = X11::OpenConnection(); - - // Create the hidden cursor - CreateHiddenCursor(); - - return true; -} - -void NzWindowImpl::Uninitialize() -{ - // Destroy the cursor - if (hiddenCursor) - { - xcb_free_cursor(connection, hiddenCursor); - hiddenCursor = 0; - } - - X11::CloseConnection(connection); - - X11::Uninitialize(); -} - -void NzWindowImpl::CleanUp() -{ - // Restore the previous video mode (in case we were running in fullscreen) - ResetVideoMode(); -} - -xcb_keysym_t NzWindowImpl::ConvertKeyCodeToKeySym(xcb_keycode_t keycode, uint16_t state) -{ - xcb_key_symbols_t* keysyms = X11::XCBKeySymbolsAlloc(connection); - if (!keysyms) - { - NazaraError("Failed to get key symbols"); - return XCB_NONE; - } - - int col = state & XCB_MOD_MASK_SHIFT ? 1 : 0; - const int altGrOffset = 4; - if (state & XCB_MOD_MASK_5) - col += altGrOffset; - xcb_keysym_t keysym = xcb_key_symbols_get_keysym(keysyms, keycode, col); - if (keysym == XCB_NO_SYMBOL) - keysym = xcb_key_symbols_get_keysym(keysyms, keycode, col ^ 0x1); - X11::XCBKeySymbolsFree(keysyms); - - return keysym; -} - -NzKeyboard::Key NzWindowImpl::ConvertVirtualKey(xcb_keysym_t symbol) -{ - // First convert to uppercase (to avoid dealing with two different keysyms for the same key) - KeySym lower, key; - XConvertCase(symbol, &lower, &key); - - switch (key) - { - // Lettres - case XK_A: return NzKeyboard::A; - case XK_B: return NzKeyboard::B; - case XK_C: return NzKeyboard::C; - case XK_D: return NzKeyboard::D; - case XK_E: return NzKeyboard::E; - case XK_F: return NzKeyboard::F; - case XK_G: return NzKeyboard::G; - case XK_H: return NzKeyboard::H; - case XK_I: return NzKeyboard::I; - case XK_J: return NzKeyboard::J; - case XK_K: return NzKeyboard::K; - case XK_L: return NzKeyboard::L; - case XK_M: return NzKeyboard::M; - case XK_N: return NzKeyboard::N; - case XK_O: return NzKeyboard::O; - case XK_P: return NzKeyboard::P; - case XK_Q: return NzKeyboard::Q; - case XK_R: return NzKeyboard::R; - case XK_S: return NzKeyboard::S; - case XK_T: return NzKeyboard::T; - case XK_U: return NzKeyboard::U; - case XK_V: return NzKeyboard::V; - case XK_W: return NzKeyboard::W; - case XK_X: return NzKeyboard::X; - case XK_Y: return NzKeyboard::Y; - case XK_Z: return NzKeyboard::Z; - - // Touches de fonction - case XK_F1: return NzKeyboard::F1; - case XK_F2: return NzKeyboard::F2; - case XK_F3: return NzKeyboard::F3; - case XK_F4: return NzKeyboard::F4; - case XK_F5: return NzKeyboard::F5; - case XK_F6: return NzKeyboard::F6; - case XK_F7: return NzKeyboard::F7; - case XK_F8: return NzKeyboard::F8; - case XK_F9: return NzKeyboard::F9; - case XK_F10: return NzKeyboard::F10; - case XK_F11: return NzKeyboard::F11; - case XK_F12: return NzKeyboard::F12; - case XK_F13: return NzKeyboard::F13; - case XK_F14: return NzKeyboard::F14; - case XK_F15: return NzKeyboard::F15; - - // Flèches directionnelles - case XK_Down: return NzKeyboard::Down; - case XK_Left: return NzKeyboard::Left; - case XK_Right: return NzKeyboard::Right; - case XK_Up: return NzKeyboard::Up; - - // Pavé numérique - case XK_KP_Add: return NzKeyboard::Add; - case XK_KP_Decimal: return NzKeyboard::Decimal; - case XK_KP_Delete: return NzKeyboard::Decimal; - case XK_KP_Divide: return NzKeyboard::Divide; - case XK_KP_Multiply: return NzKeyboard::Multiply; - case XK_KP_Insert: return NzKeyboard::Numpad0; - case XK_KP_End: return NzKeyboard::Numpad1; - case XK_KP_Down: return NzKeyboard::Numpad2; - case XK_KP_Page_Down: return NzKeyboard::Numpad3; - case XK_KP_Left: return NzKeyboard::Numpad4; - case XK_KP_Begin: return NzKeyboard::Numpad5; - case XK_KP_Right: return NzKeyboard::Numpad6; - case XK_KP_Home: return NzKeyboard::Numpad7; - case XK_KP_Up: return NzKeyboard::Numpad8; - case XK_KP_Page_Up: return NzKeyboard::Numpad9; - case XK_KP_Enter: return NzKeyboard::Return; - case XK_KP_Subtract: return NzKeyboard::Subtract; - - // Divers - case XK_backslash: return NzKeyboard::Backslash; - case XK_BackSpace: return NzKeyboard::Backspace; - case XK_Clear: return NzKeyboard::Clear; - case XK_comma: return NzKeyboard::Comma; - case XK_minus: return NzKeyboard::Dash; - case XK_Delete: return NzKeyboard::Delete; - case XK_End: return NzKeyboard::End; - case XK_equal: return NzKeyboard::Equal; - case XK_Escape: return NzKeyboard::Escape; - case XK_Home: return NzKeyboard::Home; - case XK_Insert: return NzKeyboard::Insert; - case XK_Alt_L: return NzKeyboard::LAlt; - case XK_bracketleft: return NzKeyboard::LBracket; - case XK_Control_L: return NzKeyboard::LControl; - case XK_Shift_L: return NzKeyboard::LShift; - case XK_Super_L: return NzKeyboard::LSystem; - case XK_0: return NzKeyboard::Num0; - case XK_1: return NzKeyboard::Num1; - case XK_2: return NzKeyboard::Num2; - case XK_3: return NzKeyboard::Num3; - case XK_4: return NzKeyboard::Num4; - case XK_5: return NzKeyboard::Num5; - case XK_6: return NzKeyboard::Num6; - case XK_7: return NzKeyboard::Num7; - case XK_8: return NzKeyboard::Num8; - case XK_9: return NzKeyboard::Num9; - case XK_Page_Down: return NzKeyboard::PageDown; - case XK_Page_Up: return NzKeyboard::PageUp; - case XK_Pause: return NzKeyboard::Pause; - case XK_period: return NzKeyboard::Period; - case XK_Print: return NzKeyboard::Print; - case XK_Sys_Req: return NzKeyboard::PrintScreen; - case XK_quotedbl: return NzKeyboard::Quote; - case XK_Alt_R: return NzKeyboard::RAlt; - case XK_bracketright: return NzKeyboard::RBracket; - case XK_Control_R: return NzKeyboard::RControl; - case XK_Return: return NzKeyboard::Return; - case XK_Shift_R: return NzKeyboard::RShift; - case XK_Super_R: return NzKeyboard::RSystem; - case XK_semicolon: return NzKeyboard::Semicolon; - case XK_slash: return NzKeyboard::Slash; - case XK_space: return NzKeyboard::Space; - case XK_Tab: return NzKeyboard::Tab; - case XK_grave: return NzKeyboard::Tilde; - - // Touches navigateur - case XF86XK_Back: return NzKeyboard::Browser_Back; - case XF86XK_Favorites: return NzKeyboard::Browser_Favorites; - case XF86XK_Forward: return NzKeyboard::Browser_Forward; - case XF86XK_HomePage: return NzKeyboard::Browser_Home; - case XF86XK_Refresh: return NzKeyboard::Browser_Refresh; - case XF86XK_Search: return NzKeyboard::Browser_Search; - case XF86XK_Stop: return NzKeyboard::Browser_Stop; - - // Touches de contrôle - case XF86XK_AudioNext: return NzKeyboard::Media_Next; - case XF86XK_AudioPlay: return NzKeyboard::Media_Play; - case XF86XK_AudioPrev: return NzKeyboard::Media_Previous; - case XF86XK_AudioStop: return NzKeyboard::Media_Stop; - - // Touches de contrôle du volume - case XF86XK_AudioLowerVolume: return NzKeyboard::Volume_Down; - case XF86XK_AudioMute: return NzKeyboard::Volume_Mute; - case XF86XK_AudioRaiseVolume: return NzKeyboard::Volume_Up; - - // Touches à verrouillage - case XK_Caps_Lock: return NzKeyboard::CapsLock; - case XK_Num_Lock: return NzKeyboard::NumLock; - case XK_Scroll_Lock: return NzKeyboard::ScrollLock; - - default: - return NzKeyboard::Undefined; - } -} - -const char* NzWindowImpl::ConvertWindowCursorToXName(nzWindowCursor cursor) -{ - // http://gnome-look.org/content/preview.php?preview=1&id=128170&file1=128170-1.png&file2=&file3=&name=Dummy+X11+cursors&PHPSESSID=6 - switch (cursor) - { - case nzWindowCursor_Crosshair: - return "crosshair"; - case nzWindowCursor_Default: - return "left_ptr"; - case nzWindowCursor_Hand: - return "hand"; - case nzWindowCursor_Help: - return "help"; - case nzWindowCursor_Move: - return "fleur"; - case nzWindowCursor_None: - return "none"; // Handled in set cursor - case nzWindowCursor_Pointer: - return "hand"; - case nzWindowCursor_Progress: - return "watch"; - case nzWindowCursor_ResizeE: - return "right_side"; - case nzWindowCursor_ResizeN: - return "top_side"; - case nzWindowCursor_ResizeNE: - return "top_right_corner"; - case nzWindowCursor_ResizeNW: - return "top_left_corner"; - case nzWindowCursor_ResizeS: - return "bottom_side"; - case nzWindowCursor_ResizeSE: - return "bottom_right_corner"; - case nzWindowCursor_ResizeSW: - return "bottom_left_corner"; - case nzWindowCursor_ResizeW: - return "left_side"; - case nzWindowCursor_Text: - return "xterm"; - case nzWindowCursor_Wait: - return "watch"; - } - - NazaraError("Cursor is not handled by enumeration"); - return "X_cursor"; -} - -void NzWindowImpl::CommonInitialize() -{ - // Show the window - SetVisible(true); - - // Raise the window and grab input focus - SetFocus(); - - xcb_atom_t protocols[] = - { - X11::GetAtom("WM_DELETE_WINDOW"), - }; - - if (!X11::CheckCookie( - connection, - xcb_icccm_set_wm_protocols( - connection, - m_window, - X11::GetAtom("WM_PROTOCOLS"), - sizeof(protocols), - protocols - )) - ) - NazaraError("Failed to get atom for deleting a window"); - - // Flush the commands queue - xcb_flush(connection); -} - -void NzWindowImpl::ProcessEvent(xcb_generic_event_t* windowEvent) -{ - if (!m_eventListener) - return; - - // Convert the xcb event to a NzEvent - switch (windowEvent->response_type & ~0x80) - { - // Destroy event - case XCB_DESTROY_NOTIFY: - { - // The window is about to be destroyed: we must cleanup resources - CleanUp(); - break; - } - - // Gain focus event - case XCB_FOCUS_IN: - { - const uint32_t value_list[] = { eventMask }; - xcb_change_window_attributes(connection, m_window, XCB_CW_EVENT_MASK, value_list); - - NzEvent event; - event.type = nzEventType_GainedFocus; - m_parent->PushEvent(event); - - break; - } - - // Lost focus event - case XCB_FOCUS_OUT: - { - NzEvent event; - event.type = nzEventType_LostFocus; - m_parent->PushEvent(event); - - const uint32_t values[] = { XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE }; - xcb_change_window_attributes(connection, m_window, XCB_CW_EVENT_MASK, values); - - break; - } - - // Resize event - case XCB_CONFIGURE_NOTIFY: - { - xcb_configure_notify_event_t* configureNotifyEvent = (xcb_configure_notify_event_t*)windowEvent; - // ConfigureNotify can be triggered for other reasons, check if the size has actually changed - if ((configureNotifyEvent->width != m_size_hints.width) || (configureNotifyEvent->height != m_size_hints.width)) - { - NzEvent event; - event.type = nzEventType_Resized; - event.size.width = configureNotifyEvent->width; - event.size.height = configureNotifyEvent->height; - m_parent->PushEvent(event); - - m_size_hints.width = configureNotifyEvent->width; - m_size_hints.height = configureNotifyEvent->height; - } - if ((configureNotifyEvent->x != m_size_hints.x) || (configureNotifyEvent->y != m_size_hints.y)) - { - NzEvent event; - event.type = nzEventType_Moved; - event.size.width = configureNotifyEvent->x; - event.size.height = configureNotifyEvent->y; - m_parent->PushEvent(event); - - m_size_hints.x = configureNotifyEvent->x; - m_size_hints.y = configureNotifyEvent->y; - } - break; - } - - // Close event - case XCB_CLIENT_MESSAGE: - { - xcb_client_message_event_t* clientMessageEvent = (xcb_client_message_event_t*)windowEvent; - - if (clientMessageEvent->type != X11::GetAtom("WM_PROTOCOLS")) - break; - if (clientMessageEvent->data.data32[0] == X11::GetAtom("WM_DELETE_WINDOW")) - { - NzEvent event; - event.type = nzEventType_Quit; - m_parent->PushEvent(event); - } - - break; - } - - // Key down event - case XCB_KEY_PRESS: - { - xcb_key_press_event_t* keyPressEvent = (xcb_key_press_event_t*)windowEvent; - - if (!m_keyRepeat && m_eventQueue.curr && m_eventQueue.next) - { - xcb_key_press_event_t* current = (xcb_key_release_event_t*)m_eventQueue.curr; - // keyPressEvent == next - - if ((current->time == keyPressEvent->time) && (current->detail == keyPressEvent->detail)) - break; - } - - auto keysym = ConvertKeyCodeToKeySym(keyPressEvent->detail, keyPressEvent->state); - - NzEvent event; - event.type = nzEventType_KeyPressed; - event.key.code = ConvertVirtualKey(keysym); - event.key.alt = keyPressEvent->state & XCB_MOD_MASK_1; - event.key.control = keyPressEvent->state & XCB_MOD_MASK_CONTROL; - event.key.shift = keyPressEvent->state & XCB_MOD_MASK_SHIFT; - event.key.system = keyPressEvent->state & XCB_MOD_MASK_4; - m_parent->PushEvent(event); - - char32_t codePoint = static_cast(keysym); - - // WTF if (std::isprint(codePoint, std::locale(""))) + handle combining ? - { - NzEvent event; - event.type = nzEventType_TextEntered; - event.text.character = codePoint; - event.text.repeated = false; - m_parent->PushEvent(event); - } - - break; - } - - // Key up event - case XCB_KEY_RELEASE: - { - xcb_key_release_event_t* keyReleaseEvent = (xcb_key_release_event_t*)windowEvent; - - if (!m_keyRepeat && m_eventQueue.curr && m_eventQueue.next) - { - // keyReleaseEvent == current - xcb_key_press_event_t* next = (xcb_key_press_event_t*)m_eventQueue.next; - - if ((keyReleaseEvent->time == next->time) && (keyReleaseEvent->detail == next->detail)) - break; - } - - auto keysym = ConvertKeyCodeToKeySym(keyReleaseEvent->detail, keyReleaseEvent->state); - - NzEvent event; - event.type = nzEventType_KeyReleased; - event.key.code = ConvertVirtualKey(keysym); - event.key.alt = keyReleaseEvent->state & XCB_MOD_MASK_1; - event.key.control = keyReleaseEvent->state & XCB_MOD_MASK_CONTROL; - event.key.shift = keyReleaseEvent->state & XCB_MOD_MASK_SHIFT; - event.key.system = keyReleaseEvent->state & XCB_MOD_MASK_4; - m_parent->PushEvent(event); - - break; - } - - // Mouse button pressed - case XCB_BUTTON_PRESS: - { - xcb_button_press_event_t* buttonPressEvent = (xcb_button_press_event_t*)windowEvent; - - NzEvent event; - event.type = nzEventType_MouseButtonPressed; - event.mouseButton.x = buttonPressEvent->event_x; - event.mouseButton.y = buttonPressEvent->event_y; - - if (buttonPressEvent->detail == XCB_BUTTON_INDEX_1) - event.mouseButton.button = NzMouse::Left; - else if (buttonPressEvent->detail == XCB_BUTTON_INDEX_2) - event.mouseButton.button = NzMouse::Middle; - else if (buttonPressEvent->detail == XCB_BUTTON_INDEX_3) - event.mouseButton.button = NzMouse::Right; - else if (buttonPressEvent->detail == XCB_BUTTON_INDEX_4) - event.mouseButton.button = NzMouse::XButton1; - else if (buttonPressEvent->detail == XCB_BUTTON_INDEX_5) - event.mouseButton.button = NzMouse::XButton2; - else - NazaraWarning("Mouse button not handled"); - - m_parent->PushEvent(event); - - break; - } - - // Mouse button released - case XCB_BUTTON_RELEASE: - { - xcb_button_release_event_t* buttonReleaseEvent = (xcb_button_release_event_t*)windowEvent; - - NzEvent event; - - switch (buttonReleaseEvent->detail) - { - case XCB_BUTTON_INDEX_4: - case XCB_BUTTON_INDEX_5: - { - event.type = nzEventType_MouseWheelMoved; - event.mouseWheel.delta = (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_4) ? 1 : -1; - break; - } - default: - { - event.type = nzEventType_MouseButtonReleased; - event.mouseButton.x = buttonReleaseEvent->event_x; - event.mouseButton.y = buttonReleaseEvent->event_y; - - if (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_1) - event.mouseButton.button = NzMouse::Left; - else if (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_2) - event.mouseButton.button = NzMouse::Middle; - else if (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_3) - event.mouseButton.button = NzMouse::Right; - else if (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_4) - event.mouseButton.button = NzMouse::XButton1; - else if (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_5) - event.mouseButton.button = NzMouse::XButton2; - else - NazaraWarning("Mouse button not handled"); - } - } - - m_parent->PushEvent(event); - - break; - } - - // Mouse moved - case XCB_MOTION_NOTIFY: - { - xcb_motion_notify_event_t* motionNotifyEvent = (xcb_motion_notify_event_t*)windowEvent; - - if (m_mousePos.x == motionNotifyEvent->event_x && m_mousePos.y == motionNotifyEvent->event_y) - break; - - NzEvent event; - event.type = nzEventType_MouseMoved; - event.mouseMove.deltaX = motionNotifyEvent->event_x - m_mousePos.x; - event.mouseMove.deltaY = motionNotifyEvent->event_y - m_mousePos.y; - event.mouseMove.x = motionNotifyEvent->event_x; - event.mouseMove.y = motionNotifyEvent->event_y; - m_parent->PushEvent(event); - - m_mousePos.x = motionNotifyEvent->event_x; - m_mousePos.y = motionNotifyEvent->event_y; - - break; - } - - // Mouse entered - case XCB_ENTER_NOTIFY: - { - NzEvent event; - event.type = nzEventType_MouseEntered; - m_parent->PushEvent(event); - - break; - } - - // Mouse left - case XCB_LEAVE_NOTIFY: - { - NzEvent event; - event.type = nzEventType_MouseLeft; - m_parent->PushEvent(event); - - break; - } - - // Parent window changed - case XCB_REPARENT_NOTIFY: - { - // Catch reparent events to properly apply fullscreen on - // some "strange" window managers (like Awesome) which - // seem to make use of temporary parents during mapping - if (m_style & nzWindowStyle_Fullscreen) - SwitchToFullscreen(); - - break; - } - } -} - -void NzWindowImpl::ResetVideoMode() -{ - if (fullscreenWindow == this) - { - // Get current screen info - NzScopedXCB error(nullptr); - - // Reset the video mode - NzScopedXCB setScreenConfig(xcb_randr_set_screen_config_reply( - connection, - xcb_randr_set_screen_config( - connection, - m_oldVideoMode.root, - XCB_CURRENT_TIME, - m_oldVideoMode.config_timestamp, - m_oldVideoMode.sizeID, - m_oldVideoMode.rotation, - m_oldVideoMode.rate + xcb_get_input_focus_unchecked( + connection ), &error )); if (error) - NazaraError("Failed to reset old screen configuration"); + NazaraError("Failed to check if window has focus"); - // Reset the fullscreen window - fullscreenWindow = nullptr; + return (reply->focus == m_window); } -} -void NzWindowImpl::SetCursor(xcb_cursor_t cursor) -{ - if (!X11::CheckCookie( - connection, - xcb_change_window_attributes( - connection, - m_window, - XCB_CW_CURSOR, - &cursor - )) - ) - NazaraError("Failed to change mouse cursor"); - - xcb_flush(connection); -} - -void NzWindowImpl::SetMotifHints() -{ - NzScopedXCB error(nullptr); - - const char MOTIF_WM_HINTS[] = "_MOTIF_WM_HINTS"; - NzScopedXCB hintsAtomReply(xcb_intern_atom_reply( - connection, - xcb_intern_atom( - connection, - 0, - sizeof(MOTIF_WM_HINTS) - 1, - MOTIF_WM_HINTS - ), - &error - )); - - if (!error && hintsAtomReply) + void WindowImpl::IgnoreNextMouseEvent(int mouseX, int mouseY) { - const uint32_t MWM_HINTS_FUNCTIONS = 1 << 0; - const uint32_t MWM_HINTS_DECORATIONS = 1 << 1; + // Petite astuce ... + m_mousePos.x = mouseX; + m_mousePos.y = mouseY; + } - //const uint32_t MWM_DECOR_ALL = 1 << 0; - const uint32_t MWM_DECOR_BORDER = 1 << 1; - const uint32_t MWM_DECOR_RESIZEH = 1 << 2; - const uint32_t MWM_DECOR_TITLE = 1 << 3; - const uint32_t MWM_DECOR_MENU = 1 << 4; - const uint32_t MWM_DECOR_MINIMIZE = 1 << 5; - const uint32_t MWM_DECOR_MAXIMIZE = 1 << 6; + bool WindowImpl::IsMinimized() const + { + ScopedXCBEWMHConnection ewmhConnection(connection); - //const uint32_t MWM_FUNC_ALL = 1 << 0; - const uint32_t MWM_FUNC_RESIZE = 1 << 1; - const uint32_t MWM_FUNC_MOVE = 1 << 2; - const uint32_t MWM_FUNC_MINIMIZE = 1 << 3; - const uint32_t MWM_FUNC_MAXIMIZE = 1 << 4; - const uint32_t MWM_FUNC_CLOSE = 1 << 5; + ScopedXCB error(nullptr); + bool isMinimized = false; - struct MotifWMHints + xcb_ewmh_get_atoms_reply_t atomReply; + if (xcb_ewmh_get_wm_state_reply(ewmhConnection, + xcb_ewmh_get_wm_state(ewmhConnection, m_window), &atomReply, &error) == 1) { - uint32_t flags; - uint32_t functions; - uint32_t decorations; - int32_t inputMode; - uint32_t state; - }; + for (unsigned int i = 0; i < atomReply.atoms_len; i++) + if (atomReply.atoms[i] == ewmhConnection->_NET_WM_STATE_HIDDEN) + isMinimized = true; - MotifWMHints hints; - hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; - hints.decorations = 0; - hints.functions = 0; - hints.inputMode = 0; - hints.state = 0; - - if (m_style & nzWindowStyle_Titlebar) - { - hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; - hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; + xcb_ewmh_get_atoms_reply_wipe(&atomReply); } - if (m_style & nzWindowStyle_Resizable) - { - hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; - hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE; - } - if (m_style & nzWindowStyle_Closable) - { - hints.decorations |= 0; - hints.functions |= MWM_FUNC_CLOSE; - } - - NzScopedXCB error(xcb_request_check( - connection, - xcb_change_property_checked( - connection, - XCB_PROP_MODE_REPLACE, - m_window, - hintsAtomReply->atom, - hintsAtomReply->atom, - 32, - 5, - &hints - ) - )); if (error) - NazaraError("xcb_change_property failed, could not set window hints"); - } - else - NazaraError("Failed to request _MOTIF_WM_HINTS atom."); -} + NazaraError("Failed to determine if window is minimized"); -void NzWindowImpl::SetVideoMode(const NzVideoMode& mode) -{ - // Skip mode switching if the new mode is equal to the desktop mode - if (mode == NzVideoMode::GetDesktopMode()) - return; - - NzScopedXCB error(nullptr); - - // Check if the RandR extension is present - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) - { - // RandR extension is not supported: we cannot use fullscreen mode - NazaraError("Fullscreen is not supported, switching to window mode"); - return; + return isMinimized; } - // Load RandR and check its version - NzScopedXCB randrVersion(xcb_randr_query_version_reply( - connection, - xcb_randr_query_version( - connection, - 1, - 1 - ), - &error - )); - - if (error) + bool WindowImpl::IsVisible() const { - NazaraError("Failed to load RandR, switching to window mode"); - return; + return !IsMinimized(); // Visibility event ? } - // Get the current configuration - NzScopedXCB config(xcb_randr_get_screen_info_reply( - connection, - xcb_randr_get_screen_info( - connection, - m_screen->root - ), - &error - )); - - if (error || !config) + void WindowImpl::ProcessEvents(bool block) { - // Failed to get the screen configuration - NazaraError("Failed to get the current screen configuration for fullscreen mode, switching to window mode"); - return; - } - - // Save the current video mode before we switch to fullscreen - m_oldVideoMode = *config.get(); - - // Get the available screen sizes - xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); - - if (!sizes || !config->nSizes) - { - NazaraError("Failed to get the fullscreen sizes, switching to window mode"); - return; - } - - // Search for a matching size - for (int i = 0; i < config->nSizes; ++i) - { - if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) - std::swap(sizes[i].height, sizes[i].width); - - if ((sizes[i].width == static_cast(mode.width)) && - (sizes[i].height == static_cast(mode.height))) + if (m_ownsWindow) { - // Switch to fullscreen mode - NzScopedXCB setScreenConfig(xcb_randr_set_screen_config_reply( + xcb_generic_event_t* event = nullptr; + + if (block) + { + event = xcb_wait_for_event(connection); + if (event) + { + UpdateEventQueue(event); + ProcessEvent(event); + } + } + else + { + event = xcb_poll_for_event(connection); + while (event) + { + UpdateEventQueue(event); + xcb_generic_event_t* tmp = xcb_poll_for_event(connection); + UpdateEventQueue(tmp); + ProcessEvent(event); + if (tmp) + ProcessEvent(tmp); + event = xcb_poll_for_event(connection); + } + } + } + } + + void WindowImpl::SetCursor(Nz::WindowCursor windowCursor) + { + if (windowCursor == Nz::WindowCursor_None) + SetCursor(hiddenCursor); + else + { + const char* name = ConvertWindowCursorToXName(windowCursor); + + xcb_cursor_context_t* ctx; + if (xcb_cursor_context_new(connection, m_screen, &ctx) >= 0) + { + xcb_cursor_t cursor = xcb_cursor_load_cursor(ctx, name); + SetCursor(cursor); + xcb_free_cursor(connection, cursor); + xcb_cursor_context_free(ctx); + } + } + } + + void WindowImpl::SetCursor(const Cursor& cursor) + { + if (!cursor.IsValid()) + { + NazaraError("Cursor is not valid"); + return; + } + + SetCursor(cursor.m_impl->GetCursor()); + } + + void WindowImpl::SetEventListener(bool listener) + { + if (m_ownsWindow) + m_eventListener = listener; + else if (listener != m_eventListener) + { + if (listener) + { + const uint32_t value_list[] = { eventMask }; + + if (!X11::CheckCookie( + connection, + xcb_change_window_attributes( + connection, + m_window, + XCB_CW_EVENT_MASK, + value_list + )) + ) + NazaraError("Failed to change event for listener"); + + m_eventListener = true; + } + else if (m_eventListener) + { + const uint32_t value_list[] = { XCB_EVENT_MASK_NO_EVENT }; + + if (!X11::CheckCookie( + connection, + xcb_change_window_attributes( + connection, + m_window, + XCB_CW_EVENT_MASK, + value_list + )) + ) + NazaraError("Failed to change event for listener"); + + m_eventListener = false; + } + } + } + + void WindowImpl::SetFocus() + { + if (!X11::CheckCookie( + connection, + xcb_set_input_focus( + connection, + XCB_INPUT_FOCUS_POINTER_ROOT, + m_window, + XCB_CURRENT_TIME + )) + ) + NazaraError("Failed to set input focus"); + + const uint32_t values[] = { XCB_STACK_MODE_ABOVE }; + + if (!X11::CheckCookie( + connection, + xcb_configure_window( + connection, + m_window, + XCB_CONFIG_WINDOW_STACK_MODE, + values + )) + ) + NazaraError("Failed to set focus"); + } + + void WindowImpl::SetIcon(const Icon& icon) + { + if (!icon.IsValid()) + { + NazaraError("Icon is not valid"); + return; + } + + xcb_pixmap_t icon_pixmap = icon.m_impl->GetIcon(); + xcb_pixmap_t mask_pixmap = icon.m_impl->GetMask(); + + ScopedXCB error(nullptr); + + xcb_icccm_wm_hints_t hints; + std::memset(&hints, 0, sizeof(hints)); + + xcb_icccm_get_wm_hints_reply( + connection, + xcb_icccm_get_wm_hints( + connection, + m_window), + &hints, + &error + ); + + if (error) + NazaraError("Failed to get wm hints"); + + xcb_icccm_wm_hints_set_icon_pixmap(&hints, icon_pixmap); + xcb_icccm_wm_hints_set_icon_mask(&hints, mask_pixmap); + + if (!X11::CheckCookie( + connection, + xcb_icccm_set_wm_hints( + connection, + m_window, + &hints + )) + ) + NazaraError("Failed to set wm hints"); + + xcb_flush(connection); + } + + void WindowImpl::SetMaximumSize(int width, int height) + { + if (width < 0) + width = m_screen->width_in_pixels; + if (height < 0) + height = m_screen->height_in_pixels; + + xcb_icccm_size_hints_set_max_size(&m_size_hints, width, height); + if (!UpdateNormalHints()) + NazaraError("Failed to set maximum size"); + + xcb_flush(connection); + } + + void WindowImpl::SetMinimumSize(int width, int height) + { + xcb_icccm_size_hints_set_min_size(&m_size_hints, width, height); + if (!UpdateNormalHints()) + NazaraError("Failed to set minimum size"); + + xcb_flush(connection); + } + + void WindowImpl::SetPosition(int x, int y) + { + xcb_icccm_size_hints_set_position(&m_size_hints, true, x, y); + if (!UpdateNormalHints()) + NazaraError("Failed to set size hints position"); + + const uint32_t values[] = { static_cast(x), static_cast(y) }; + if (!X11::CheckCookie( + connection, + xcb_configure_window( + connection, + m_window, + XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, + values + )) + ) + NazaraError("Failed to set position"); + + xcb_flush(connection); + } + + void WindowImpl::SetSize(unsigned int width, unsigned int height) + { + xcb_icccm_size_hints_set_size(&m_size_hints, true, width, height); + if (!UpdateNormalHints()) + NazaraError("Failed to set size hints sizes"); + + const uint32_t values[] = { width, height }; + if (!X11::CheckCookie( + connection, + xcb_configure_window( + connection, + m_window, + XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, + values + )) + ) + NazaraError("Failed to set sizes"); + + xcb_flush(connection); + } + + void WindowImpl::SetStayOnTop(bool stayOnTop) + { + ScopedXCBEWMHConnection ewmhConnection(connection); + + xcb_atom_t onTop; // It is not really working + if (stayOnTop) + onTop = ewmhConnection->_NET_WM_STATE_ABOVE; + else + onTop = ewmhConnection->_NET_WM_STATE_BELOW; + + if (!X11::CheckCookie( + connection, + xcb_ewmh_set_wm_state( + ewmhConnection, + m_window, + 1, + &onTop + )) + ) + NazaraError("Failed to set stay on top"); + + xcb_flush(connection); + } + + void WindowImpl::SetTitle(const String& title) + { + ScopedXCBEWMHConnection ewmhConnection(connection); + + if (!X11::CheckCookie( + connection, + xcb_ewmh_set_wm_name( + ewmhConnection, + m_window, + title.GetSize(), + title.GetConstBuffer() + )) + ) + NazaraError("Failed to set title"); + + xcb_flush(connection); + } + + void WindowImpl::SetVisible(bool visible) + { + if (visible) + { + if (!X11::CheckCookie( + connection, + xcb_map_window( + connection, + m_window + )) + ) + NazaraError("Failed to change window visibility to visible"); + } + else + { + if (!X11::CheckCookie( + connection, + xcb_unmap_window( + connection, + m_window + )) + ) + NazaraError("Failed to change window visibility to invisible"); + } + + xcb_flush(connection); + } + + bool WindowImpl::Initialize() + { + X11::Initialize(); + + connection = X11::OpenConnection(); + + // Create the hidden cursor + CreateHiddenCursor(); + + return true; + } + + void WindowImpl::Uninitialize() + { + // Destroy the cursor + if (hiddenCursor) + { + xcb_free_cursor(connection, hiddenCursor); + hiddenCursor = 0; + } + + X11::CloseConnection(connection); + + X11::Uninitialize(); + } + + void WindowImpl::CleanUp() + { + // Restore the previous video mode (in case we were running in fullscreen) + ResetVideoMode(); + } + + xcb_keysym_t WindowImpl::ConvertKeyCodeToKeySym(xcb_keycode_t keycode, uint16_t state) + { + xcb_key_symbols_t* keysyms = X11::XCBKeySymbolsAlloc(connection); + if (!keysyms) + { + NazaraError("Failed to get key symbols"); + return XCB_NONE; + } + + int col = state & XCB_MOD_MASK_SHIFT ? 1 : 0; + const int altGrOffset = 4; + if (state & XCB_MOD_MASK_5) + col += altGrOffset; + xcb_keysym_t keysym = xcb_key_symbols_get_keysym(keysyms, keycode, col); + if (keysym == XCB_NO_SYMBOL) + keysym = xcb_key_symbols_get_keysym(keysyms, keycode, col ^ 0x1); + X11::XCBKeySymbolsFree(keysyms); + + return keysym; + } + + Keyboard::Key WindowImpl::ConvertVirtualKey(xcb_keysym_t symbol) + { + // First convert to uppercase (to avoid dealing with two different keysyms for the same key) + KeySym lower, key; + XConvertCase(symbol, &lower, &key); + + switch (key) + { + // Lettres + case XK_A: return Keyboard::A; + case XK_B: return Keyboard::B; + case XK_C: return Keyboard::C; + case XK_D: return Keyboard::D; + case XK_E: return Keyboard::E; + case XK_F: return Keyboard::F; + case XK_G: return Keyboard::G; + case XK_H: return Keyboard::H; + case XK_I: return Keyboard::I; + case XK_J: return Keyboard::J; + case XK_K: return Keyboard::K; + case XK_L: return Keyboard::L; + case XK_M: return Keyboard::M; + case XK_N: return Keyboard::N; + case XK_O: return Keyboard::O; + case XK_P: return Keyboard::P; + case XK_Q: return Keyboard::Q; + case XK_R: return Keyboard::R; + case XK_S: return Keyboard::S; + case XK_T: return Keyboard::T; + case XK_U: return Keyboard::U; + case XK_V: return Keyboard::V; + case XK_W: return Keyboard::W; + case XK_X: return Keyboard::X; + case XK_Y: return Keyboard::Y; + case XK_Z: return Keyboard::Z; + + // Touches de fonction + case XK_F1: return Keyboard::F1; + case XK_F2: return Keyboard::F2; + case XK_F3: return Keyboard::F3; + case XK_F4: return Keyboard::F4; + case XK_F5: return Keyboard::F5; + case XK_F6: return Keyboard::F6; + case XK_F7: return Keyboard::F7; + case XK_F8: return Keyboard::F8; + case XK_F9: return Keyboard::F9; + case XK_F10: return Keyboard::F10; + case XK_F11: return Keyboard::F11; + case XK_F12: return Keyboard::F12; + case XK_F13: return Keyboard::F13; + case XK_F14: return Keyboard::F14; + case XK_F15: return Keyboard::F15; + + // Flèches directionnelles + case XK_Down: return Keyboard::Down; + case XK_Left: return Keyboard::Left; + case XK_Right: return Keyboard::Right; + case XK_Up: return Keyboard::Up; + + // Pavé numérique + case XK_KP_Add: return Keyboard::Add; + case XK_KP_Decimal: return Keyboard::Decimal; + case XK_KP_Delete: return Keyboard::Decimal; + case XK_KP_Divide: return Keyboard::Divide; + case XK_KP_Multiply: return Keyboard::Multiply; + case XK_KP_Insert: return Keyboard::Numpad0; + case XK_KP_End: return Keyboard::Numpad1; + case XK_KP_Down: return Keyboard::Numpad2; + case XK_KP_Page_Down: return Keyboard::Numpad3; + case XK_KP_Left: return Keyboard::Numpad4; + case XK_KP_Begin: return Keyboard::Numpad5; + case XK_KP_Right: return Keyboard::Numpad6; + case XK_KP_Home: return Keyboard::Numpad7; + case XK_KP_Up: return Keyboard::Numpad8; + case XK_KP_Page_Up: return Keyboard::Numpad9; + case XK_KP_Enter: return Keyboard::Return; + case XK_KP_Subtract: return Keyboard::Subtract; + + // Divers + case XK_backslash: return Keyboard::Backslash; + case XK_BackSpace: return Keyboard::Backspace; + case XK_Clear: return Keyboard::Clear; + case XK_comma: return Keyboard::Comma; + case XK_minus: return Keyboard::Dash; + case XK_Delete: return Keyboard::Delete; + case XK_End: return Keyboard::End; + case XK_equal: return Keyboard::Equal; + case XK_Escape: return Keyboard::Escape; + case XK_Home: return Keyboard::Home; + case XK_Insert: return Keyboard::Insert; + case XK_Alt_L: return Keyboard::LAlt; + case XK_bracketleft: return Keyboard::LBracket; + case XK_Control_L: return Keyboard::LControl; + case XK_Shift_L: return Keyboard::LShift; + case XK_Super_L: return Keyboard::LSystem; + case XK_0: return Keyboard::Num0; + case XK_1: return Keyboard::Num1; + case XK_2: return Keyboard::Num2; + case XK_3: return Keyboard::Num3; + case XK_4: return Keyboard::Num4; + case XK_5: return Keyboard::Num5; + case XK_6: return Keyboard::Num6; + case XK_7: return Keyboard::Num7; + case XK_8: return Keyboard::Num8; + case XK_9: return Keyboard::Num9; + case XK_Page_Down: return Keyboard::PageDown; + case XK_Page_Up: return Keyboard::PageUp; + case XK_Pause: return Keyboard::Pause; + case XK_period: return Keyboard::Period; + case XK_Print: return Keyboard::Print; + case XK_Sys_Req: return Keyboard::PrintScreen; + case XK_quotedbl: return Keyboard::Quote; + case XK_Alt_R: return Keyboard::RAlt; + case XK_bracketright: return Keyboard::RBracket; + case XK_Control_R: return Keyboard::RControl; + case XK_Return: return Keyboard::Return; + case XK_Shift_R: return Keyboard::RShift; + case XK_Super_R: return Keyboard::RSystem; + case XK_semicolon: return Keyboard::Semicolon; + case XK_slash: return Keyboard::Slash; + case XK_space: return Keyboard::Space; + case XK_Tab: return Keyboard::Tab; + case XK_grave: return Keyboard::Tilde; + + // Touches navigateur + case XF86XK_Back: return Keyboard::Browser_Back; + case XF86XK_Favorites: return Keyboard::Browser_Favorites; + case XF86XK_Forward: return Keyboard::Browser_Forward; + case XF86XK_HomePage: return Keyboard::Browser_Home; + case XF86XK_Refresh: return Keyboard::Browser_Refresh; + case XF86XK_Search: return Keyboard::Browser_Search; + case XF86XK_Stop: return Keyboard::Browser_Stop; + + // Touches de contrôle + case XF86XK_AudioNext: return Keyboard::Media_Next; + case XF86XK_AudioPlay: return Keyboard::Media_Play; + case XF86XK_AudioPrev: return Keyboard::Media_Previous; + case XF86XK_AudioStop: return Keyboard::Media_Stop; + + // Touches de contrôle du volume + case XF86XK_AudioLowerVolume: return Keyboard::Volume_Down; + case XF86XK_AudioMute: return Keyboard::Volume_Mute; + case XF86XK_AudioRaiseVolume: return Keyboard::Volume_Up; + + // Touches à verrouillage + case XK_Caps_Lock: return Keyboard::CapsLock; + case XK_Num_Lock: return Keyboard::NumLock; + case XK_Scroll_Lock: return Keyboard::ScrollLock; + + default: + return Keyboard::Undefined; + } + } + + const char* WindowImpl::ConvertWindowCursorToXName(Nz::WindowCursor cursor) + { + // http://gnome-look.org/content/preview.php?preview=1&id=128170&file1=128170-1.png&file2=&file3=&name=Dummy+X11+cursors&PHPSESSID=6 + switch (cursor) + { + case Nz::WindowCursor_Crosshair: + return "crosshair"; + case Nz::WindowCursor_Default: + return "left_ptr"; + case Nz::WindowCursor_Hand: + return "hand"; + case Nz::WindowCursor_Help: + return "help"; + case Nz::WindowCursor_Move: + return "fleur"; + case Nz::WindowCursor_None: + return "none"; // Handled in set cursor + case Nz::WindowCursor_Pointer: + return "hand"; + case Nz::WindowCursor_Progress: + return "watch"; + case Nz::WindowCursor_ResizeE: + return "right_side"; + case Nz::WindowCursor_ResizeN: + return "top_side"; + case Nz::WindowCursor_ResizeNE: + return "top_right_corner"; + case Nz::WindowCursor_ResizeNW: + return "top_left_corner"; + case Nz::WindowCursor_ResizeS: + return "bottom_side"; + case Nz::WindowCursor_ResizeSE: + return "bottom_right_corner"; + case Nz::WindowCursor_ResizeSW: + return "bottom_left_corner"; + case Nz::WindowCursor_ResizeW: + return "left_side"; + case Nz::WindowCursor_Text: + return "xterm"; + case Nz::WindowCursor_Wait: + return "watch"; + } + + NazaraError("Cursor is not handled by enumeration"); + return "X_cursor"; + } + + void WindowImpl::CommonInitialize() + { + // Show the window + SetVisible(true); + + // Raise the window and grab input focus + SetFocus(); + + xcb_atom_t protocols[] = + { + X11::GetAtom("WM_DELETE_WINDOW"), + }; + + if (!X11::CheckCookie( + connection, + xcb_icccm_set_wm_protocols( + connection, + m_window, + X11::GetAtom("WM_PROTOCOLS"), + sizeof(protocols), + protocols + )) + ) + NazaraError("Failed to get atom for deleting a window"); + + // Flush the commands queue + xcb_flush(connection); + } + + void WindowImpl::ProcessEvent(xcb_generic_event_t* windowEvent) + { + if (!m_eventListener) + return; + + // Convert the xcb event to a Event + switch (windowEvent->response_type & ~0x80) + { + // Destroy event + case XCB_DESTROY_NOTIFY: + { + // The window is about to be destroyed: we must cleanup resources + CleanUp(); + break; + } + + // Gain focus event + case XCB_FOCUS_IN: + { + const uint32_t value_list[] = { eventMask }; + xcb_change_window_attributes(connection, m_window, XCB_CW_EVENT_MASK, value_list); + + WindowEvent event; + event.type = Nz::WindowEventType_GainedFocus; + m_parent->PushEvent(event); + + break; + } + + // Lost focus event + case XCB_FOCUS_OUT: + { + WindowEvent event; + event.type = Nz::WindowEventType_LostFocus; + m_parent->PushEvent(event); + + const uint32_t values[] = { XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE }; + xcb_change_window_attributes(connection, m_window, XCB_CW_EVENT_MASK, values); + + break; + } + + // Resize event + case XCB_CONFIGURE_NOTIFY: + { + xcb_configure_notify_event_t* configureNotifyEvent = (xcb_configure_notify_event_t*)windowEvent; + // ConfigureNotify can be triggered for other reasons, check if the size has actually changed + if ((configureNotifyEvent->width != m_size_hints.width) || (configureNotifyEvent->height != m_size_hints.width)) + { + WindowEvent event; + event.type = Nz::WindowEventType_Resized; + event.size.width = configureNotifyEvent->width; + event.size.height = configureNotifyEvent->height; + m_parent->PushEvent(event); + + m_size_hints.width = configureNotifyEvent->width; + m_size_hints.height = configureNotifyEvent->height; + } + if ((configureNotifyEvent->x != m_size_hints.x) || (configureNotifyEvent->y != m_size_hints.y)) + { + WindowEvent event; + event.type = Nz::WindowEventType_Moved; + event.size.width = configureNotifyEvent->x; + event.size.height = configureNotifyEvent->y; + m_parent->PushEvent(event); + + m_size_hints.x = configureNotifyEvent->x; + m_size_hints.y = configureNotifyEvent->y; + } + break; + } + + // Close event + case XCB_CLIENT_MESSAGE: + { + xcb_client_message_event_t* clientMessageEvent = (xcb_client_message_event_t*)windowEvent; + + if (clientMessageEvent->type != X11::GetAtom("WM_PROTOCOLS")) + break; + if (clientMessageEvent->data.data32[0] == X11::GetAtom("WM_DELETE_WINDOW")) + { + WindowEvent event; + event.type = Nz::WindowEventType_Quit; + m_parent->PushEvent(event); + } + + break; + } + + // Key down event + case XCB_KEY_PRESS: + { + xcb_key_press_event_t* keyPressEvent = (xcb_key_press_event_t*)windowEvent; + + if (!m_keyRepeat && m_eventQueue.curr && m_eventQueue.next) + { + xcb_key_press_event_t* current = (xcb_key_release_event_t*)m_eventQueue.curr; + // keyPressEvent == next + + if ((current->time == keyPressEvent->time) && (current->detail == keyPressEvent->detail)) + break; + } + + auto keysym = ConvertKeyCodeToKeySym(keyPressEvent->detail, keyPressEvent->state); + + WindowEvent event; + event.type = Nz::WindowEventType_KeyPressed; + event.key.code = ConvertVirtualKey(keysym); + event.key.alt = keyPressEvent->state & XCB_MOD_MASK_1; + event.key.control = keyPressEvent->state & XCB_MOD_MASK_CONTROL; + event.key.shift = keyPressEvent->state & XCB_MOD_MASK_SHIFT; + event.key.system = keyPressEvent->state & XCB_MOD_MASK_4; + m_parent->PushEvent(event); + + char32_t codePoint = static_cast(keysym); + + // WTF if (std::isprint(codePoint, std::locale(""))) + handle combining ? + { + WindowEvent event; + event.type = Nz::WindowEventType_TextEntered; + event.text.character = codePoint; + event.text.repeated = false; + m_parent->PushEvent(event); + } + + break; + } + + // Key up event + case XCB_KEY_RELEASE: + { + xcb_key_release_event_t* keyReleaseEvent = (xcb_key_release_event_t*)windowEvent; + + if (!m_keyRepeat && m_eventQueue.curr && m_eventQueue.next) + { + // keyReleaseEvent == current + xcb_key_press_event_t* next = (xcb_key_press_event_t*)m_eventQueue.next; + + if ((keyReleaseEvent->time == next->time) && (keyReleaseEvent->detail == next->detail)) + break; + } + + auto keysym = ConvertKeyCodeToKeySym(keyReleaseEvent->detail, keyReleaseEvent->state); + + WindowEvent event; + event.type = Nz::WindowEventType_KeyReleased; + event.key.code = ConvertVirtualKey(keysym); + event.key.alt = keyReleaseEvent->state & XCB_MOD_MASK_1; + event.key.control = keyReleaseEvent->state & XCB_MOD_MASK_CONTROL; + event.key.shift = keyReleaseEvent->state & XCB_MOD_MASK_SHIFT; + event.key.system = keyReleaseEvent->state & XCB_MOD_MASK_4; + m_parent->PushEvent(event); + + break; + } + + // Mouse button pressed + case XCB_BUTTON_PRESS: + { + xcb_button_press_event_t* buttonPressEvent = (xcb_button_press_event_t*)windowEvent; + + WindowEvent event; + event.type = Nz::WindowEventType_MouseButtonPressed; + event.mouseButton.x = buttonPressEvent->event_x; + event.mouseButton.y = buttonPressEvent->event_y; + + if (buttonPressEvent->detail == XCB_BUTTON_INDEX_1) + event.mouseButton.button = Mouse::Left; + else if (buttonPressEvent->detail == XCB_BUTTON_INDEX_2) + event.mouseButton.button = Mouse::Middle; + else if (buttonPressEvent->detail == XCB_BUTTON_INDEX_3) + event.mouseButton.button = Mouse::Right; + else if (buttonPressEvent->detail == XCB_BUTTON_INDEX_4) + event.mouseButton.button = Mouse::XButton1; + else if (buttonPressEvent->detail == XCB_BUTTON_INDEX_5) + event.mouseButton.button = Mouse::XButton2; + else + NazaraWarning("Mouse button not handled"); + + m_parent->PushEvent(event); + + break; + } + + // Mouse button released + case XCB_BUTTON_RELEASE: + { + xcb_button_release_event_t* buttonReleaseEvent = (xcb_button_release_event_t*)windowEvent; + + WindowEvent event; + + switch (buttonReleaseEvent->detail) + { + case XCB_BUTTON_INDEX_4: + case XCB_BUTTON_INDEX_5: + { + event.type = Nz::WindowEventType_MouseWheelMoved; + event.mouseWheel.delta = (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_4) ? 1 : -1; + break; + } + default: + { + event.type = Nz::WindowEventType_MouseButtonReleased; + event.mouseButton.x = buttonReleaseEvent->event_x; + event.mouseButton.y = buttonReleaseEvent->event_y; + + if (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_1) + event.mouseButton.button = Mouse::Left; + else if (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_2) + event.mouseButton.button = Mouse::Middle; + else if (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_3) + event.mouseButton.button = Mouse::Right; + else if (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_4) + event.mouseButton.button = Mouse::XButton1; + else if (buttonReleaseEvent->detail == XCB_BUTTON_INDEX_5) + event.mouseButton.button = Mouse::XButton2; + else + NazaraWarning("Mouse button not handled"); + } + } + + m_parent->PushEvent(event); + + break; + } + + // Mouse moved + case XCB_MOTION_NOTIFY: + { + xcb_motion_notify_event_t* motionNotifyEvent = (xcb_motion_notify_event_t*)windowEvent; + + if (m_mousePos.x == motionNotifyEvent->event_x && m_mousePos.y == motionNotifyEvent->event_y) + break; + + WindowEvent event; + event.type = Nz::WindowEventType_MouseMoved; + event.mouseMove.deltaX = motionNotifyEvent->event_x - m_mousePos.x; + event.mouseMove.deltaY = motionNotifyEvent->event_y - m_mousePos.y; + event.mouseMove.x = motionNotifyEvent->event_x; + event.mouseMove.y = motionNotifyEvent->event_y; + m_parent->PushEvent(event); + + m_mousePos.x = motionNotifyEvent->event_x; + m_mousePos.y = motionNotifyEvent->event_y; + + break; + } + + // Mouse entered + case XCB_ENTER_NOTIFY: + { + WindowEvent event; + event.type = Nz::WindowEventType_MouseEntered; + m_parent->PushEvent(event); + + break; + } + + // Mouse left + case XCB_LEAVE_NOTIFY: + { + WindowEvent event; + event.type = Nz::WindowEventType_MouseLeft; + m_parent->PushEvent(event); + + break; + } + + // Parent window changed + case XCB_REPARENT_NOTIFY: + { + // Catch reparent events to properly apply fullscreen on + // some "strange" window managers (like Awesome) which + // seem to make use of temporary parents during mapping + if (m_style & Nz::WindowStyle_Fullscreen) + SwitchToFullscreen(); + + break; + } + } + } + + void WindowImpl::ResetVideoMode() + { + if (fullscreenWindow == this) + { + // Get current screen info + ScopedXCB error(nullptr); + + // Reset the video mode + ScopedXCB setScreenConfig(xcb_randr_set_screen_config_reply( connection, xcb_randr_set_screen_config( connection, - config->root, + m_oldVideoMode.root, XCB_CURRENT_TIME, - config->config_timestamp, - i, - config->rotation, - config->rate + m_oldVideoMode.config_timestamp, + m_oldVideoMode.sizeID, + m_oldVideoMode.rotation, + m_oldVideoMode.rate ), &error )); if (error) - NazaraError("Failed to set new screen configuration"); + NazaraError("Failed to reset old screen configuration"); - // Set "this" as the current fullscreen window - fullscreenWindow = this; - return; + // Reset the fullscreen window + fullscreenWindow = nullptr; } } - NazaraError("Failed to find matching fullscreen size, switching to window mode"); -} - -void NzWindowImpl::SwitchToFullscreen() -{ - SetFocus(); - - NzScopedXCBEWMHConnection ewmhConnection(connection); - - if (!X11::CheckCookie( - connection, - xcb_ewmh_set_wm_state( - ewmhConnection, - m_window, - 1, - &ewmhConnection->_NET_WM_STATE_FULLSCREEN - )) - ) - NazaraError("Failed to switch to fullscreen"); -} - -void NzWindowImpl::UpdateEventQueue(xcb_generic_event_t* event) -{ - std::free(m_eventQueue.curr); - m_eventQueue.curr = m_eventQueue.next; - m_eventQueue.next = event; -} - -bool NzWindowImpl::UpdateNormalHints() -{ - return X11::CheckCookie( - connection, - xcb_icccm_set_wm_normal_hints( + void WindowImpl::SetCursor(xcb_cursor_t cursor) + { + if (!X11::CheckCookie( connection, - m_window, - &m_size_hints + xcb_change_window_attributes( + connection, + m_window, + XCB_CW_CURSOR, + &cursor + )) + ) + NazaraError("Failed to change mouse cursor"); + + xcb_flush(connection); + } + + void WindowImpl::SetMotifHints() + { + ScopedXCB error(nullptr); + + const char MOTIF_WM_HINTS[] = "_MOTIF_WM_HINTS"; + ScopedXCB hintsAtomReply(xcb_intern_atom_reply( + connection, + xcb_intern_atom( + connection, + 0, + sizeof(MOTIF_WM_HINTS) - 1, + MOTIF_WM_HINTS + ), + &error )); + + if (!error && hintsAtomReply) + { + const uint32_t MWM_HINTS_FUNCTIONS = 1 << 0; + const uint32_t MWM_HINTS_DECORATIONS = 1 << 1; + + //const uint32_t MWM_DECOR_ALL = 1 << 0; + const uint32_t MWM_DECOR_BORDER = 1 << 1; + const uint32_t MWM_DECOR_RESIZEH = 1 << 2; + const uint32_t MWM_DECOR_TITLE = 1 << 3; + const uint32_t MWM_DECOR_MENU = 1 << 4; + const uint32_t MWM_DECOR_MINIMIZE = 1 << 5; + const uint32_t MWM_DECOR_MAXIMIZE = 1 << 6; + + //const uint32_t MWM_FUNC_ALL = 1 << 0; + const uint32_t MWM_FUNC_RESIZE = 1 << 1; + const uint32_t MWM_FUNC_MOVE = 1 << 2; + const uint32_t MWM_FUNC_MINIMIZE = 1 << 3; + const uint32_t MWM_FUNC_MAXIMIZE = 1 << 4; + const uint32_t MWM_FUNC_CLOSE = 1 << 5; + + struct MotifWMHints + { + uint32_t flags; + uint32_t functions; + uint32_t decorations; + int32_t inputMode; + uint32_t state; + }; + + MotifWMHints hints; + hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; + hints.decorations = 0; + hints.functions = 0; + hints.inputMode = 0; + hints.state = 0; + + if (m_style & Nz::WindowStyle_Titlebar) + { + hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; + hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; + } + if (m_style & Nz::WindowStyle_Resizable) + { + hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; + hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE; + } + if (m_style & Nz::WindowStyle_Closable) + { + hints.decorations |= 0; + hints.functions |= MWM_FUNC_CLOSE; + } + + ScopedXCB error(xcb_request_check( + connection, + xcb_change_property_checked( + connection, + XCB_PROP_MODE_REPLACE, + m_window, + hintsAtomReply->atom, + hintsAtomReply->atom, + 32, + 5, + &hints + ) + )); + + if (error) + NazaraError("xcb_change_property failed, could not set window hints"); + } + else + NazaraError("Failed to request _MOTIF_WM_HINTS atom."); + } + + void WindowImpl::SetVideoMode(const VideoMode& mode) + { + // Skip mode switching if the new mode is equal to the desktop mode + if (mode == VideoMode::GetDesktopMode()) + return; + + ScopedXCB error(nullptr); + + // Check if the RandR extension is present + const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); + + if (!randrExt || !randrExt->present) + { + // RandR extension is not supported: we cannot use fullscreen mode + NazaraError("Fullscreen is not supported, switching to window mode"); + return; + } + + // Load RandR and check its version + ScopedXCB randrVersion(xcb_randr_query_version_reply( + connection, + xcb_randr_query_version( + connection, + 1, + 1 + ), + &error + )); + + if (error) + { + NazaraError("Failed to load RandR, switching to window mode"); + return; + } + + // Get the current configuration + ScopedXCB config(xcb_randr_get_screen_info_reply( + connection, + xcb_randr_get_screen_info( + connection, + m_screen->root + ), + &error + )); + + if (error || !config) + { + // Failed to get the screen configuration + NazaraError("Failed to get the current screen configuration for fullscreen mode, switching to window mode"); + return; + } + + // Save the current video mode before we switch to fullscreen + m_oldVideoMode = *config.get(); + + // Get the available screen sizes + xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); + + if (!sizes || !config->nSizes) + { + NazaraError("Failed to get the fullscreen sizes, switching to window mode"); + return; + } + + // Search for a matching size + for (int i = 0; i < config->nSizes; ++i) + { + if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || + config->rotation == XCB_RANDR_ROTATION_ROTATE_270) + std::swap(sizes[i].height, sizes[i].width); + + if ((sizes[i].width == static_cast(mode.width)) && + (sizes[i].height == static_cast(mode.height))) + { + // Switch to fullscreen mode + ScopedXCB setScreenConfig(xcb_randr_set_screen_config_reply( + connection, + xcb_randr_set_screen_config( + connection, + config->root, + XCB_CURRENT_TIME, + config->config_timestamp, + i, + config->rotation, + config->rate + ), + &error + )); + + if (error) + NazaraError("Failed to set new screen configuration"); + + // Set "this" as the current fullscreen window + fullscreenWindow = this; + return; + } + } + + NazaraError("Failed to find matching fullscreen size, switching to window mode"); + } + + void WindowImpl::SwitchToFullscreen() + { + SetFocus(); + + ScopedXCBEWMHConnection ewmhConnection(connection); + + if (!X11::CheckCookie( + connection, + xcb_ewmh_set_wm_state( + ewmhConnection, + m_window, + 1, + &ewmhConnection->_NET_WM_STATE_FULLSCREEN + )) + ) + NazaraError("Failed to switch to fullscreen"); + } + + void WindowImpl::UpdateEventQueue(xcb_generic_event_t* event) + { + std::free(m_eventQueue.curr); + m_eventQueue.curr = m_eventQueue.next; + m_eventQueue.next = event; + } + + bool WindowImpl::UpdateNormalHints() + { + return X11::CheckCookie( + connection, + xcb_icccm_set_wm_normal_hints( + connection, + m_window, + &m_size_hints + )); + } + + #if NAZARA_UTILITY_THREADED_WINDOW + void WindowImpl::WindowThread(WindowImpl* window, Mutex* mutex, ConditionVariable* condition) + { + mutex->Lock(); + condition->Signal(); + mutex->Unlock(); // mutex et condition sont considérés invalides à partir d'ici + + if (!window->m_window) + return; + + while (window->m_threadActive) + window->ProcessEvents(true); + + window->Destroy(); + } + #endif } - -#if NAZARA_UTILITY_THREADED_WINDOW -void NzWindowImpl::WindowThread(NzWindowImpl* window, NzMutex* mutex, NzConditionVariable* condition) -{ - mutex->Lock(); - condition->Signal(); - mutex->Unlock(); // mutex et condition sont considérés invalides à partir d'ici - - if (!window->m_window) - return; - - while (window->m_threadActive) - window->ProcessEvents(true); - - window->Destroy(); -} -#endif diff --git a/src/Nazara/Utility/X11/WindowImpl.hpp b/src/Nazara/Utility/X11/WindowImpl.hpp index 8245699b2..6a0e26391 100644 --- a/src/Nazara/Utility/X11/WindowImpl.hpp +++ b/src/Nazara/Utility/X11/WindowImpl.hpp @@ -9,118 +9,127 @@ #ifndef NAZARA_WINDOWIMPL_HPP #define NAZARA_WINDOWIMPL_HPP -#include +#include #include #include #include #include +#include #include #include -#include -#if NAZARA_UTILITY_THREADED_WINDOW -class NzConditionVariable; -class NzMutex; -#endif -class NzCursor; -class NzIcon; -class NzVideoMode; -class NzWindow; - -class NzWindowImpl : NzNonCopyable +namespace Nz { - public: - NzWindowImpl(NzWindow* parent); - ~NzWindowImpl(); + #if NAZARA_UTILITY_THREADED_WINDOW + class ConditionVariable; + class Mutex; + #endif + class Cursor; + class Icon; + class VideoMode; + class Window; - bool Create(const NzVideoMode& mode, const NzString& title, nzUInt32 style); - bool Create(NzWindowHandle handle); + class WindowImpl + { + public: + WindowImpl(Window* parent); + WindowImpl(const WindowImpl&) = delete; + WindowImpl(WindowImpl&&) = delete; ///TODO? + ~WindowImpl(); - void Destroy(); + bool Create(const VideoMode& mode, const String& title, UInt32 style); + bool Create(WindowHandle handle); - void EnableKeyRepeat(bool enable); - void EnableSmoothScrolling(bool enable); + void Destroy(); - NzWindowHandle GetHandle() const; - unsigned int GetHeight() const; - NzVector2i GetPosition() const; - NzVector2ui GetSize() const; - nzUInt32 GetStyle() const; - NzString GetTitle() const; - unsigned int GetWidth() const; + void EnableKeyRepeat(bool enable); + void EnableSmoothScrolling(bool enable); - bool HasFocus() const; + WindowHandle GetHandle() const; + unsigned int GetHeight() const; + Vector2i GetPosition() const; + Vector2ui GetSize() const; + UInt32 GetStyle() const; + String GetTitle() const; + unsigned int GetWidth() const; - void IgnoreNextMouseEvent(int mouseX, int mouseY); + bool HasFocus() const; - bool IsMinimized() const; - bool IsVisible() const; + void IgnoreNextMouseEvent(int mouseX, int mouseY); - void ProcessEvents(bool block); + bool IsMinimized() const; + bool IsVisible() const; - void SetCursor(nzWindowCursor cursor); - void SetCursor(const NzCursor& cursor); - void SetEventListener(bool listener); - void SetFocus(); - void SetIcon(const NzIcon& icon); - void SetMaximumSize(int width, int height); - void SetMinimumSize(int width, int height); - void SetPosition(int x, int y); - void SetSize(unsigned int width, unsigned int height); - void SetStayOnTop(bool stayOnTop); - void SetTitle(const NzString& title); - void SetVisible(bool visible); + void ProcessEvents(bool block); - static bool Initialize(); - static void Uninitialize(); + void SetCursor(WindowCursor cursor); + void SetCursor(const Cursor& cursor); + void SetEventListener(bool listener); + void SetFocus(); + void SetIcon(const Icon& icon); + void SetMaximumSize(int width, int height); + void SetMinimumSize(int width, int height); + void SetPosition(int x, int y); + void SetSize(unsigned int width, unsigned int height); + void SetStayOnTop(bool stayOnTop); + void SetTitle(const String& title); + void SetVisible(bool visible); - private: + WindowImpl& operator=(const WindowImpl&) = delete; + WindowImpl& operator=(WindowImpl&&) = delete; ///TODO? - void CleanUp(); - xcb_keysym_t ConvertKeyCodeToKeySym(xcb_keycode_t keycode, uint16_t state); - NzKeyboard::Key ConvertVirtualKey(xcb_keysym_t symbol); - const char* ConvertWindowCursorToXName(nzWindowCursor cursor); - void CommonInitialize(); + static bool Initialize(); + static void Uninitialize(); - void ProcessEvent(xcb_generic_event_t* windowEvent); + private: - void ResetVideoMode(); + void CleanUp(); + xcb_keysym_t ConvertKeyCodeToKeySym(xcb_keycode_t keycode, uint16_t state); + Keyboard::Key ConvertVirtualKey(xcb_keysym_t symbol); + const char* ConvertWindowCursorToXName(WindowCursor cursor); + void CommonInitialize(); - void SetCursor(xcb_cursor_t cursor); - void SetMotifHints(); - void SetVideoMode(const NzVideoMode& mode); - void SwitchToFullscreen(); + void ProcessEvent(xcb_generic_event_t* windowEvent); - bool UpdateNormalHints(); - void UpdateEventQueue(xcb_generic_event_t* event); + void ResetVideoMode(); - #if NAZARA_UTILITY_THREADED_WINDOW - static void WindowThread(NzWindowImpl* window, NzMutex* mutex, NzConditionVariable* condition); - #endif + void SetCursor(xcb_cursor_t cursor); + void SetMotifHints(); + void SetVideoMode(const VideoMode& mode); + void SwitchToFullscreen(); - xcb_window_t m_window; - xcb_screen_t* m_screen; - xcb_randr_get_screen_info_reply_t m_oldVideoMode; - xcb_size_hints_t m_size_hints; - nzUInt32 m_style; - #if NAZARA_UTILITY_THREADED_WINDOW - NzThread m_thread; - #endif - NzWindow* m_parent; - bool m_eventListener; - bool m_ownsWindow; - bool m_smoothScrolling; - #if NAZARA_UTILITY_THREADED_WINDOW - bool m_threadActive; - #endif - short m_scrolling; - NzVector2i m_mousePos; - bool m_keyRepeat; + bool UpdateNormalHints(); + void UpdateEventQueue(xcb_generic_event_t* event); + + #if NAZARA_UTILITY_THREADED_WINDOW + static void WindowThread(WindowImpl* window, Mutex* mutex, ConditionVariable* condition); + #endif + + xcb_window_t m_window; + xcb_screen_t* m_screen; + xcb_randr_get_screen_info_reply_t m_oldVideoMode; + xcb_size_hints_t m_size_hints; + UInt32 m_style; + #if NAZARA_UTILITY_THREADED_WINDOW + Thread m_thread; + #endif + Window* m_parent; + bool m_eventListener; + bool m_ownsWindow; + bool m_smoothScrolling; + #if NAZARA_UTILITY_THREADED_WINDOW + bool m_threadActive; + #endif + short m_scrolling; + Vector2i m_mousePos; + bool m_keyRepeat; + + struct + { + xcb_generic_event_t* curr = nullptr; + xcb_generic_event_t* next = nullptr; + } m_eventQueue; + }; +} - struct - { - xcb_generic_event_t* curr = nullptr; - xcb_generic_event_t* next = nullptr; - } m_eventQueue; -}; #endif // NAZARA_WINDOWIMPL_HPP