New module: Platform - Split window management from Utility module (#128)
* New module: Platform - Split window management from Utility module Final touch * NDK/SDK: Bring back initialization of Utility
This commit is contained in:
committed by
Jérôme Leclercq
parent
41a1b5d493
commit
5aa072cee3
87
src/Nazara/Platform/Cursor.cpp
Normal file
87
src/Nazara/Platform/Cursor.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Cursor.hpp>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Platform/Win32/CursorImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_X11)
|
||||
#include <Nazara/Platform/X11/CursorImpl.hpp>
|
||||
#else
|
||||
#error Lack of implementation: Cursor
|
||||
#endif
|
||||
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool Cursor::Create(const Image& cursor, const Vector2i& hotSpot, SystemCursor placeholder)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
std::unique_ptr<CursorImpl> impl(new CursorImpl);
|
||||
if (!impl->Create(cursor, hotSpot.x, hotSpot.y))
|
||||
{
|
||||
NazaraError("Failed to create cursor implementation");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_cursorImage = cursor;
|
||||
m_impl = impl.release();
|
||||
m_systemCursor = placeholder;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cursor::Destroy()
|
||||
{
|
||||
m_cursorImage.Destroy();
|
||||
|
||||
if (m_impl)
|
||||
{
|
||||
m_impl->Destroy();
|
||||
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Cursor::Create(SystemCursor cursor)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
std::unique_ptr<CursorImpl> impl(new CursorImpl);
|
||||
if (!impl->Create(cursor))
|
||||
{
|
||||
NazaraError("Failed to create cursor implementation");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl.release();
|
||||
m_systemCursor = cursor;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cursor::Initialize()
|
||||
{
|
||||
if (!CursorImpl::Initialize())
|
||||
return false;
|
||||
|
||||
for (std::size_t i = 0; i <= SystemCursor_Max; ++i)
|
||||
s_systemCursors[i].Create(static_cast<SystemCursor>(i));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cursor::Uninitialize()
|
||||
{
|
||||
for (Cursor& cursor : s_systemCursors)
|
||||
cursor.Destroy();
|
||||
|
||||
CursorImpl::Uninitialize();
|
||||
}
|
||||
|
||||
std::array<Cursor, SystemCursor_Max + 1> Cursor::s_systemCursors;
|
||||
}
|
||||
31
src/Nazara/Platform/Debug/NewOverload.cpp
Normal file
31
src/Nazara/Platform/Debug/NewOverload.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Config.hpp>
|
||||
#if NAZARA_PLATFORM_MANAGE_MEMORY
|
||||
|
||||
#include <Nazara/Core/MemoryManager.hpp>
|
||||
#include <new> // Needed ?
|
||||
|
||||
void* operator new(std::size_t size)
|
||||
{
|
||||
return Nz::MemoryManager::Allocate(size, false);
|
||||
}
|
||||
|
||||
void* operator new[](std::size_t size)
|
||||
{
|
||||
return Nz::MemoryManager::Allocate(size, true);
|
||||
}
|
||||
|
||||
void operator delete(void* pointer) noexcept
|
||||
{
|
||||
Nz::MemoryManager::Free(pointer, false);
|
||||
}
|
||||
|
||||
void operator delete[](void* pointer) noexcept
|
||||
{
|
||||
Nz::MemoryManager::Free(pointer, true);
|
||||
}
|
||||
|
||||
#endif // NAZARA_PLATFORM_MANAGE_MEMORY
|
||||
45
src/Nazara/Platform/Icon.cpp
Normal file
45
src/Nazara/Platform/Icon.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Icon.hpp>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Platform/Win32/IconImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_X11)
|
||||
#include <Nazara/Platform/X11/IconImpl.hpp>
|
||||
#else
|
||||
#error Lack of implementation: Icon
|
||||
#endif
|
||||
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool Icon::Create(const Image& icon)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
std::unique_ptr<IconImpl> impl(new IconImpl);
|
||||
if (!impl->Create(icon))
|
||||
{
|
||||
NazaraError("Failed to create icon implementation");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Icon::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
m_impl->Destroy();
|
||||
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/Nazara/Platform/Keyboard.cpp
Normal file
28
src/Nazara/Platform/Keyboard.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Keyboard.hpp>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Platform/Win32/InputImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_X11)
|
||||
#include <Nazara/Platform/X11/InputImpl.hpp>
|
||||
#else
|
||||
#error Lack of implementation: Keyboard
|
||||
#endif
|
||||
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
String Keyboard::GetKeyName(Key key)
|
||||
{
|
||||
return EventImpl::GetKeyName(key);
|
||||
}
|
||||
|
||||
bool Keyboard::IsKeyPressed(Key key)
|
||||
{
|
||||
return EventImpl::IsKeyPressed(key);
|
||||
}
|
||||
}
|
||||
60
src/Nazara/Platform/Mouse.cpp
Normal file
60
src/Nazara/Platform/Mouse.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Mouse.hpp>
|
||||
#include <Nazara/Platform/Window.hpp>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Platform/Win32/InputImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_X11)
|
||||
#include <Nazara/Platform/X11/InputImpl.hpp>
|
||||
#else
|
||||
#error Lack of implementation: Mouse
|
||||
#endif
|
||||
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
Vector2i Mouse::GetPosition()
|
||||
{
|
||||
return EventImpl::GetMousePosition();
|
||||
}
|
||||
|
||||
Vector2i Mouse::GetPosition(const Window& relativeTo)
|
||||
{
|
||||
return EventImpl::GetMousePosition(relativeTo);
|
||||
}
|
||||
|
||||
bool Mouse::IsButtonPressed(Button button)
|
||||
{
|
||||
return EventImpl::IsMouseButtonPressed(button);
|
||||
}
|
||||
|
||||
void Mouse::SetPosition(const Vector2i& position)
|
||||
{
|
||||
EventImpl::SetMousePosition(position.x, position.y);
|
||||
}
|
||||
|
||||
void Mouse::SetPosition(const Vector2i& position, const Window& relativeTo, bool ignoreEvent)
|
||||
{
|
||||
if (ignoreEvent && position.x > 0 && position.y > 0)
|
||||
relativeTo.IgnoreNextMouseEvent(position.x, position.y);
|
||||
|
||||
EventImpl::SetMousePosition(position.x, position.y, relativeTo);
|
||||
}
|
||||
|
||||
void Mouse::SetPosition(int x, int y)
|
||||
{
|
||||
EventImpl::SetMousePosition(x, y);
|
||||
}
|
||||
|
||||
void Mouse::SetPosition(int x, int y, const Window& relativeTo, bool ignoreEvent)
|
||||
{
|
||||
if (ignoreEvent && x > 0 && y > 0)
|
||||
relativeTo.IgnoreNextMouseEvent(x, y);
|
||||
|
||||
EventImpl::SetMousePosition(x, y, relativeTo);
|
||||
}
|
||||
}
|
||||
108
src/Nazara/Platform/Platform.cpp
Normal file
108
src/Nazara/Platform/Platform.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Platform.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Platform/Config.hpp>
|
||||
#include <Nazara/Platform/Cursor.hpp>
|
||||
#include <Nazara/Platform/Window.hpp>
|
||||
#include <Nazara/Utility/Utility.hpp>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup system
|
||||
* \class Nz::Platform
|
||||
* \brief Platform class that represents the module initializer of Platform
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Initializes the Platform module
|
||||
* \return true if initialization is successful
|
||||
*
|
||||
* \remark Produces a NazaraNotice
|
||||
* \remark Produces a NazaraError if one submodule failed
|
||||
*/
|
||||
|
||||
bool Platform::Initialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
{
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Already initialized
|
||||
}
|
||||
|
||||
// Initialize module dependencies
|
||||
if (!Utility::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize utility module");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter++;
|
||||
|
||||
// Initialisation of the module
|
||||
CallOnExit onExit(Platform::Uninitialize);
|
||||
|
||||
if (!Window::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize window's system");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Must be initialized after Window
|
||||
if (!Cursor::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize cursors");
|
||||
return false;
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
NazaraNotice("Initialized: Platform module");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the module is initialized
|
||||
* \return true if module is initialized
|
||||
*/
|
||||
|
||||
bool Platform::IsInitialized()
|
||||
{
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the Platform module
|
||||
*
|
||||
* \remark Produces a NazaraNotice
|
||||
*/
|
||||
|
||||
void Platform::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
{
|
||||
// The module is still in use, or can not be uninitialized
|
||||
if (s_moduleReferenceCounter > 1)
|
||||
s_moduleReferenceCounter--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Free of module
|
||||
s_moduleReferenceCounter = 0;
|
||||
|
||||
Cursor::Uninitialize(); //< Must be done before Window
|
||||
Window::Uninitialize();
|
||||
|
||||
NazaraNotice("Uninitialized: Platform module");
|
||||
|
||||
// Free of dependances
|
||||
Utility::Uninitialize();
|
||||
}
|
||||
|
||||
unsigned int Platform::s_moduleReferenceCounter = 0;
|
||||
}
|
||||
109
src/Nazara/Platform/VideoMode.cpp
Normal file
109
src/Nazara/Platform/VideoMode.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/VideoMode.hpp>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Platform/Win32/VideoModeImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_X11)
|
||||
#include <Nazara/Platform/X11/VideoModeImpl.hpp>
|
||||
#else
|
||||
#error Lack of implementation: Window
|
||||
#endif
|
||||
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
VideoMode::VideoMode() :
|
||||
bitsPerPixel(0),
|
||||
height(0),
|
||||
width(0)
|
||||
{
|
||||
}
|
||||
|
||||
VideoMode::VideoMode(unsigned int w, unsigned int h) :
|
||||
VideoMode(w, h, GetDesktopMode().bitsPerPixel)
|
||||
{
|
||||
}
|
||||
|
||||
VideoMode::VideoMode(unsigned int w, unsigned int h, UInt8 bpp) :
|
||||
bitsPerPixel(bpp),
|
||||
height(h),
|
||||
width(w)
|
||||
{
|
||||
}
|
||||
|
||||
bool VideoMode::IsFullscreenValid() const
|
||||
{
|
||||
const std::vector<VideoMode>& modes = GetFullscreenModes();
|
||||
|
||||
return std::binary_search(modes.begin(), modes.end(), *this, std::greater<VideoMode>());
|
||||
}
|
||||
|
||||
VideoMode VideoMode::GetDesktopMode()
|
||||
{
|
||||
return VideoModeImpl::GetDesktopMode();
|
||||
}
|
||||
|
||||
const std::vector<VideoMode>& VideoMode::GetFullscreenModes()
|
||||
{
|
||||
static std::vector<VideoMode> modes;
|
||||
if (modes.empty())
|
||||
{
|
||||
VideoModeImpl::GetFullscreenModes(modes);
|
||||
std::sort(modes.begin(), modes.end(), std::greater<VideoMode>());
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
bool operator==(const VideoMode& left, const VideoMode& right)
|
||||
{
|
||||
return left.width == right.width && left.height == right.height && left.bitsPerPixel == right.bitsPerPixel;
|
||||
}
|
||||
|
||||
bool operator!=(const VideoMode& left, const VideoMode& right)
|
||||
{
|
||||
return left.width != right.width || left.height != right.height || left.bitsPerPixel != right.bitsPerPixel;
|
||||
}
|
||||
|
||||
bool operator<(const VideoMode& left, const VideoMode& right)
|
||||
{
|
||||
if (left.bitsPerPixel == right.bitsPerPixel)
|
||||
{
|
||||
if (left.width == right.width)
|
||||
return left.height < right.height;
|
||||
else
|
||||
return left.width < right.width;
|
||||
}
|
||||
else
|
||||
return left.bitsPerPixel < right.bitsPerPixel;
|
||||
}
|
||||
|
||||
bool operator<=(const VideoMode& left, const VideoMode& right)
|
||||
{
|
||||
if (left.bitsPerPixel == right.bitsPerPixel)
|
||||
{
|
||||
if (left.width == right.width)
|
||||
return left.height <= right.height;
|
||||
else
|
||||
return left.width < right.width;
|
||||
}
|
||||
else
|
||||
return left.bitsPerPixel < right.bitsPerPixel;
|
||||
}
|
||||
|
||||
bool operator>(const VideoMode& left, const VideoMode& right)
|
||||
{
|
||||
return right < left;
|
||||
}
|
||||
|
||||
bool operator>=(const VideoMode& left, const VideoMode& right)
|
||||
{
|
||||
return right <= left;
|
||||
}
|
||||
}
|
||||
21
src/Nazara/Platform/VideoModeImpl.hpp
Normal file
21
src/Nazara/Platform/VideoModeImpl.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_VIDEOMODEIMPL_HPP
|
||||
#define NAZARA_VIDEOMODEIMPL_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
class VideoMode;
|
||||
|
||||
class VideoModeImpl
|
||||
{
|
||||
public:
|
||||
static VideoMode GetDesktopMode();
|
||||
static void GetFullscreenModes(std::vector<VideoMode>& modes);
|
||||
};
|
||||
|
||||
#endif // NAZARA_VIDEOMODEIMPL_HPP
|
||||
106
src/Nazara/Platform/Win32/CursorImpl.cpp
Normal file
106
src/Nazara/Platform/Win32/CursorImpl.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Win32/CursorImpl.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Utility/Image.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool CursorImpl::Create(const Image& cursor, int hotSpotX, int hotSpotY)
|
||||
{
|
||||
Image windowsCursor(cursor);
|
||||
if (!windowsCursor.Convert(PixelFormatType_BGRA8))
|
||||
{
|
||||
NazaraError("Failed to convert cursor to BGRA8");
|
||||
return false;
|
||||
}
|
||||
|
||||
HBITMAP bitmap = CreateBitmap(windowsCursor.GetWidth(), windowsCursor.GetHeight(), 1, 32, windowsCursor.GetConstPixels());
|
||||
HBITMAP monoBitmap = CreateBitmap(windowsCursor.GetWidth(), windowsCursor.GetHeight(), 1, 1, nullptr);
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648052(v=vs.85).aspx
|
||||
ICONINFO iconInfo;
|
||||
iconInfo.fIcon = FALSE;
|
||||
iconInfo.xHotspot = hotSpotX;
|
||||
iconInfo.yHotspot = hotSpotY;
|
||||
iconInfo.hbmMask = monoBitmap;
|
||||
iconInfo.hbmColor = bitmap;
|
||||
|
||||
m_icon = CreateIconIndirect(&iconInfo);
|
||||
|
||||
DeleteObject(bitmap);
|
||||
DeleteObject(monoBitmap);
|
||||
|
||||
if (!m_icon)
|
||||
{
|
||||
NazaraError("Failed to create cursor: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_cursor = m_icon;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CursorImpl::Create(SystemCursor cursor)
|
||||
{
|
||||
if (cursor != SystemCursor_Move)
|
||||
m_cursor = static_cast<HCURSOR>(LoadImage(nullptr, s_systemCursorIds[cursor], IMAGE_CURSOR, 0, 0, LR_SHARED));
|
||||
else
|
||||
m_cursor = nullptr;
|
||||
|
||||
// No need to free the cursor if shared
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx
|
||||
m_icon = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CursorImpl::Destroy()
|
||||
{
|
||||
if (m_icon)
|
||||
DestroyIcon(m_icon);
|
||||
}
|
||||
|
||||
HCURSOR CursorImpl::GetCursor()
|
||||
{
|
||||
return m_cursor;
|
||||
}
|
||||
|
||||
bool CursorImpl::Initialize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CursorImpl::Uninitialize()
|
||||
{
|
||||
}
|
||||
|
||||
std::array<LPTSTR, SystemCursor_Max + 1> CursorImpl::s_systemCursorIds =
|
||||
{
|
||||
IDC_CROSS, // SystemCursor_Crosshair
|
||||
IDC_ARROW, // SystemCursor_Default
|
||||
IDC_HAND, // SystemCursor_Hand
|
||||
IDC_HELP, // SystemCursor_Help
|
||||
IDC_SIZEALL, // SystemCursor_Move
|
||||
nullptr, // SystemCursor_None
|
||||
IDC_HAND, // SystemCursor_Pointer
|
||||
IDC_APPSTARTING, // SystemCursor_Progress
|
||||
IDC_SIZEWE, // SystemCursor_ResizeE
|
||||
IDC_SIZENS, // SystemCursor_ResizeN
|
||||
IDC_SIZENESW, // SystemCursor_ResizeNE
|
||||
IDC_SIZENWSE, // SystemCursor_ResizeNW
|
||||
IDC_SIZENS, // SystemCursor_ResizeS
|
||||
IDC_SIZENWSE, // SystemCursor_ResizeSE
|
||||
IDC_SIZENESW, // SystemCursor_ResizeSW
|
||||
IDC_SIZEWE, // SystemCursor_ResizeW
|
||||
IDC_IBEAM, // SystemCursor_Text
|
||||
IDC_WAIT // SystemCursor_Wait
|
||||
};
|
||||
|
||||
static_assert(SystemCursor_Max + 1 == 18, "System cursor array is incomplete");
|
||||
}
|
||||
42
src/Nazara/Platform/Win32/CursorImpl.hpp
Normal file
42
src/Nazara/Platform/Win32/CursorImpl.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_CURSORIMPL_HPP
|
||||
#define NAZARA_CURSORIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Platform/Enums.hpp>
|
||||
#include <array>
|
||||
#include <windows.h>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class Image;
|
||||
|
||||
class CursorImpl
|
||||
{
|
||||
friend class Cursor;
|
||||
|
||||
public:
|
||||
bool Create(const Image& image, int hotSpotX, int hotSpotY);
|
||||
bool Create(SystemCursor cursor);
|
||||
|
||||
void Destroy();
|
||||
|
||||
HCURSOR GetCursor();
|
||||
|
||||
private:
|
||||
static bool Initialize();
|
||||
static void Uninitialize();
|
||||
|
||||
HCURSOR m_cursor = nullptr;
|
||||
HICON m_icon = nullptr;
|
||||
|
||||
static std::array<LPTSTR, SystemCursor_Max + 1> s_systemCursorIds;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_CURSORIMPL_HPP
|
||||
53
src/Nazara/Platform/Win32/IconImpl.cpp
Normal file
53
src/Nazara/Platform/Win32/IconImpl.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Win32/IconImpl.hpp>
|
||||
#include <Nazara/Utility/Image.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool IconImpl::Create(const Image& icon)
|
||||
{
|
||||
Image windowsIcon(icon); // Vive le COW
|
||||
if (!windowsIcon.Convert(PixelFormatType_BGRA8))
|
||||
{
|
||||
NazaraError("Failed to convert icon to BGRA8");
|
||||
return false;
|
||||
}
|
||||
|
||||
HBITMAP bitmap = CreateBitmap(windowsIcon.GetWidth(), windowsIcon.GetHeight(), 1, 32, windowsIcon.GetConstPixels());
|
||||
HBITMAP monoBitmap = CreateBitmap(windowsIcon.GetWidth(), windowsIcon.GetHeight(), 1, 1, nullptr);
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648052(v=vs.85).aspx
|
||||
ICONINFO iconInfo;
|
||||
iconInfo.fIcon = TRUE;
|
||||
iconInfo.hbmMask = monoBitmap;
|
||||
iconInfo.hbmColor = bitmap;
|
||||
|
||||
m_icon = CreateIconIndirect(&iconInfo);
|
||||
|
||||
DeleteObject(bitmap);
|
||||
DeleteObject(monoBitmap);
|
||||
|
||||
if (!m_icon)
|
||||
{
|
||||
NazaraError("Failed to create icon: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IconImpl::Destroy()
|
||||
{
|
||||
DestroyIcon(m_icon);
|
||||
}
|
||||
|
||||
HICON IconImpl::GetIcon()
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
}
|
||||
30
src/Nazara/Platform/Win32/IconImpl.hpp
Normal file
30
src/Nazara/Platform/Win32/IconImpl.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_ICONIMPL_HPP
|
||||
#define NAZARA_ICONIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class Image;
|
||||
|
||||
class IconImpl
|
||||
{
|
||||
public:
|
||||
bool Create(const Image& image);
|
||||
void Destroy();
|
||||
|
||||
HICON GetIcon();
|
||||
|
||||
private:
|
||||
HICON m_icon = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_ICONIMPL_HPP
|
||||
296
src/Nazara/Platform/Win32/InputImpl.cpp
Normal file
296
src/Nazara/Platform/Win32/InputImpl.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Win32/InputImpl.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Platform/Window.hpp>
|
||||
#include <windows.h>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
int vKeys[Keyboard::Count] = {
|
||||
// Lettres
|
||||
0x41, // Key::A
|
||||
0x42, // Key::B
|
||||
0x43, // Key::C
|
||||
0x44, // Key::D
|
||||
0x45, // Key::E
|
||||
0x46, // Key::F
|
||||
0x47, // Key::G
|
||||
0x48, // Key::H
|
||||
0x49, // Key::I
|
||||
0x4A, // Key::J
|
||||
0x4B, // Key::K
|
||||
0x4C, // Key::L
|
||||
0x4D, // Key::M
|
||||
0x4E, // Key::N
|
||||
0x4F, // Key::O
|
||||
0x50, // Key::P
|
||||
0x51, // Key::Q
|
||||
0x52, // Key::R
|
||||
0x53, // Key::S
|
||||
0x54, // Key::T
|
||||
0x55, // Key::U
|
||||
0x56, // Key::V
|
||||
0x57, // Key::W
|
||||
0x58, // Key::X
|
||||
0x59, // Key::Y
|
||||
0x5A, // Key::Z
|
||||
|
||||
// Touches de fonction
|
||||
VK_F1, // Key::F1
|
||||
VK_F2, // Key::F2
|
||||
VK_F3, // Key::F3
|
||||
VK_F4, // Key::F4
|
||||
VK_F5, // Key::F5
|
||||
VK_F6, // Key::F6
|
||||
VK_F7, // Key::F7
|
||||
VK_F8, // Key::F8
|
||||
VK_F9, // Key::F9
|
||||
VK_F10, // Key::F10
|
||||
VK_F11, // Key::F11
|
||||
VK_F12, // Key::F12
|
||||
VK_F13, // Key::F13
|
||||
VK_F14, // Key::F14
|
||||
VK_F15, // Key::F15
|
||||
|
||||
// Flèches directionnelles
|
||||
VK_DOWN, // Key::Down
|
||||
VK_LEFT, // Key::Left
|
||||
VK_RIGHT, // Key::Right
|
||||
VK_UP, // Key::Up
|
||||
|
||||
// Pavé numérique
|
||||
VK_ADD, // Key::Add
|
||||
VK_DECIMAL, // Key::Decimal
|
||||
VK_DIVIDE, // Key::Divide
|
||||
VK_MULTIPLY, // Key::Multiply
|
||||
VK_NUMPAD0, // Key::Numpad0
|
||||
VK_NUMPAD1, // Key::Numpad1
|
||||
VK_NUMPAD2, // Key::Numpad2
|
||||
VK_NUMPAD3, // Key::Numpad3
|
||||
VK_NUMPAD4, // Key::Numpad4
|
||||
VK_NUMPAD5, // Key::Numpad5
|
||||
VK_NUMPAD6, // Key::Numpad6
|
||||
VK_NUMPAD7, // Key::Numpad7
|
||||
VK_NUMPAD8, // Key::Numpad8
|
||||
VK_NUMPAD9, // Key::Numpad9
|
||||
VK_SUBTRACT, // Key::Subtract
|
||||
|
||||
// Diverss
|
||||
VK_OEM_5, // Key::Backslash
|
||||
VK_BACK, // Key::Backspace
|
||||
VK_CLEAR, // Key::Clear
|
||||
VK_OEM_COMMA, // Key::Comma,
|
||||
VK_OEM_MINUS, // Key::Dash
|
||||
VK_DELETE, // Key::Delete
|
||||
VK_END, // Key::End
|
||||
VK_OEM_PLUS, // Key::Equal
|
||||
VK_ESCAPE, // Key::Escape
|
||||
VK_HOME, // Key::Home
|
||||
VK_INSERT, // Key::Insert
|
||||
VK_LMENU, // Key::LAlt
|
||||
VK_OEM_4, // Key::LBracket
|
||||
VK_LCONTROL, // Key::LControl
|
||||
VK_LSHIFT, // Key::LShift
|
||||
VK_LWIN, // Key::LSystem
|
||||
0x30, // Key::Num0
|
||||
0x31, // Key::Num1
|
||||
0x32, // Key::Num2
|
||||
0x33, // Key::Num3
|
||||
0x34, // Key::Num4
|
||||
0x35, // Key::Num5
|
||||
0x36, // Key::Num6
|
||||
0x37, // Key::Num7
|
||||
0x38, // Key::Num8
|
||||
0x39, // Key::Num9
|
||||
VK_NEXT, // Key::PageDown
|
||||
VK_PRIOR, // Key::PageUp
|
||||
VK_PAUSE, // Key::Pause
|
||||
VK_OEM_PERIOD, // Key::Period
|
||||
VK_PRINT, // Key::Print
|
||||
VK_SNAPSHOT, // Key::PrintScreen
|
||||
VK_OEM_7, // Key::Quote
|
||||
VK_RMENU, // Key::RAlt
|
||||
VK_OEM_6, // Key::RBracket
|
||||
VK_RCONTROL, // Key::RControl
|
||||
VK_RETURN, // Key::Return
|
||||
VK_RSHIFT, // Key::RShift
|
||||
VK_RWIN, // Key::RSystem
|
||||
VK_OEM_1, // Key::Semicolon
|
||||
VK_OEM_2, // Key::Slash
|
||||
VK_SPACE, // Key::Space
|
||||
VK_TAB, // Key::Tab
|
||||
VK_OEM_3, // Key::Tilde
|
||||
|
||||
// Touches navigateur
|
||||
VK_BROWSER_BACK, // Key::Browser_Back
|
||||
VK_BROWSER_FAVORITES, // Key::Browser_Favorites
|
||||
VK_BROWSER_FORWARD, // Key::Browser_Forward
|
||||
VK_BROWSER_HOME, // Key::Browser_Home
|
||||
VK_BROWSER_REFRESH, // Key::Browser_Refresh
|
||||
VK_BROWSER_SEARCH, // Key::Browser_Search
|
||||
VK_BROWSER_STOP, // Key::Browser_Stop
|
||||
|
||||
// Touches de contrôle
|
||||
VK_MEDIA_NEXT_TRACK, // Key::Media_Next,
|
||||
VK_MEDIA_PLAY_PAUSE, // Key::Media_PlayPause,
|
||||
VK_MEDIA_PREV_TRACK, // Key::Media_Previous,
|
||||
VK_MEDIA_STOP, // Key::Media_Stop,
|
||||
|
||||
// Touches de contrôle du volume
|
||||
VK_VOLUME_DOWN, // Key::Volume_Down
|
||||
VK_VOLUME_MUTE, // Key::Volume_Mute
|
||||
VK_VOLUME_UP, // Key::Volume_Up
|
||||
|
||||
// Touches à verrouillage
|
||||
VK_CAPITAL, // Key::CapsLock
|
||||
VK_NUMLOCK, // Key::NumLock
|
||||
VK_SCROLL // Key::ScrollLock
|
||||
};
|
||||
}
|
||||
|
||||
String EventImpl::GetKeyName(Keyboard::Key key)
|
||||
{
|
||||
// http://www.ffuts.org/blog/mapvirtualkey-getkeynametext-and-a-story-of-how-to/
|
||||
int vk = vKeys[key];
|
||||
unsigned int code = MapVirtualKeyW(vk, 0) << 16;
|
||||
|
||||
///FIXME: Liste complète ?
|
||||
switch (vk)
|
||||
{
|
||||
case VK_ATTN:
|
||||
case VK_DOWN:
|
||||
case VK_DECIMAL:
|
||||
case VK_DELETE:
|
||||
case VK_DIVIDE:
|
||||
case VK_END:
|
||||
case VK_HOME:
|
||||
case VK_INSERT:
|
||||
case VK_LEFT:
|
||||
case VK_LWIN:
|
||||
case VK_OEM_1:
|
||||
case VK_OEM_2:
|
||||
case VK_OEM_3:
|
||||
case VK_OEM_4:
|
||||
case VK_OEM_5:
|
||||
case VK_OEM_6:
|
||||
case VK_OEM_7:
|
||||
case VK_OEM_CLEAR:
|
||||
case VK_OEM_COMMA:
|
||||
case VK_OEM_MINUS:
|
||||
case VK_OEM_PERIOD:
|
||||
case VK_OEM_PLUS:
|
||||
case VK_PAUSE:
|
||||
case VK_NEXT:
|
||||
case VK_NUMLOCK:
|
||||
case VK_PRIOR:
|
||||
case VK_RIGHT:
|
||||
case VK_RWIN:
|
||||
case VK_UP:
|
||||
code |= 0x1000000; // 24ème bit pour l'extension
|
||||
break;
|
||||
}
|
||||
|
||||
wchar_t keyName[20]; // Je ne pense pas que ça dépassera 20 caractères
|
||||
if (!GetKeyNameTextW(code, &keyName[0], 20))
|
||||
return "Unknown";
|
||||
|
||||
return String::Unicode(keyName);
|
||||
}
|
||||
|
||||
Vector2i EventImpl::GetMousePosition()
|
||||
{
|
||||
POINT pos;
|
||||
GetCursorPos(&pos);
|
||||
|
||||
return Vector2i(pos.x, pos.y);
|
||||
}
|
||||
|
||||
Vector2i EventImpl::GetMousePosition(const Window& relativeTo)
|
||||
{
|
||||
HWND handle = static_cast<HWND>(relativeTo.GetHandle());
|
||||
if (handle)
|
||||
{
|
||||
POINT pos;
|
||||
GetCursorPos(&pos);
|
||||
ScreenToClient(handle, &pos);
|
||||
|
||||
return Vector2i(pos.x, pos.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Invalid window handle");
|
||||
|
||||
// Attention que (-1, -1) est une position tout à fait valide et ne doit pas servir de test
|
||||
return Vector2i(-1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
bool EventImpl::IsKeyPressed(Keyboard::Key key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case Keyboard::CapsLock:
|
||||
case Keyboard::NumLock:
|
||||
case Keyboard::ScrollLock:
|
||||
return GetKeyState(vKeys[key]) != 0;
|
||||
|
||||
default:
|
||||
return (GetAsyncKeyState(vKeys[key]) & 0x8000) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool EventImpl::IsMouseButtonPressed(Mouse::Button button)
|
||||
{
|
||||
static int vButtons[Mouse::Max+1] = {
|
||||
VK_LBUTTON, // Button::Left
|
||||
VK_MBUTTON, // Button::Middle
|
||||
VK_RBUTTON, // Button::Right
|
||||
VK_XBUTTON1, // Button::XButton1
|
||||
VK_XBUTTON2 // Button::XButton2
|
||||
};
|
||||
|
||||
// Gestion de l'inversement des boutons de la souris
|
||||
if (GetSystemMetrics(SM_SWAPBUTTON))
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case Mouse::Left:
|
||||
button = Mouse::Right;
|
||||
break;
|
||||
|
||||
case Mouse::Right:
|
||||
button = Mouse::Left;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (GetAsyncKeyState(vButtons[button]) & 0x8000) != 0;
|
||||
}
|
||||
|
||||
void EventImpl::SetMousePosition(int x, int y)
|
||||
{
|
||||
SetCursorPos(x, y);
|
||||
}
|
||||
|
||||
void EventImpl::SetMousePosition(int x, int y, const Window& relativeTo)
|
||||
{
|
||||
HWND handle = static_cast<HWND>(relativeTo.GetHandle());
|
||||
if (handle)
|
||||
{
|
||||
POINT pos = {x, y};
|
||||
ClientToScreen(handle, &pos);
|
||||
SetCursorPos(pos.x, pos.y);
|
||||
}
|
||||
else
|
||||
NazaraError("Invalid window handle");
|
||||
}
|
||||
}
|
||||
30
src/Nazara/Platform/Win32/InputImpl.hpp
Normal file
30
src/Nazara/Platform/Win32/InputImpl.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_INPUTIMPL_HPP
|
||||
#define NAZARA_INPUTIMPL_HPP
|
||||
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <Nazara/Platform/Keyboard.hpp>
|
||||
#include <Nazara/Platform/Mouse.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
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
|
||||
35
src/Nazara/Platform/Win32/VideoModeImpl.cpp
Normal file
35
src/Nazara/Platform/Win32/VideoModeImpl.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Win32/VideoModeImpl.hpp>
|
||||
#include <Nazara/Platform/VideoMode.hpp>
|
||||
#include <algorithm>
|
||||
#include <windows.h>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
VideoMode VideoModeImpl::GetDesktopMode()
|
||||
{
|
||||
DEVMODE mode;
|
||||
mode.dmSize = sizeof(DEVMODE);
|
||||
EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &mode);
|
||||
|
||||
return VideoMode(mode.dmPelsWidth, mode.dmPelsHeight, static_cast<UInt8>(mode.dmBitsPerPel));
|
||||
}
|
||||
|
||||
void VideoModeImpl::GetFullscreenModes(std::vector<VideoMode>& modes)
|
||||
{
|
||||
DEVMODE win32Mode;
|
||||
win32Mode.dmSize = sizeof(DEVMODE);
|
||||
for (unsigned int i = 0; EnumDisplaySettings(nullptr, i, &win32Mode); ++i)
|
||||
{
|
||||
VideoMode mode(win32Mode.dmPelsWidth, win32Mode.dmPelsHeight, static_cast<UInt8>(win32Mode.dmBitsPerPel));
|
||||
|
||||
// Il existe plusieurs modes avec ces trois caractéristques identiques
|
||||
if (std::find(modes.begin(), modes.end(), mode) == modes.end())
|
||||
modes.push_back(mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/Nazara/Platform/Win32/VideoModeImpl.hpp
Normal file
22
src/Nazara/Platform/Win32/VideoModeImpl.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_VIDEOMODEIMPL_HPP
|
||||
#define NAZARA_VIDEOMODEIMPL_HPP
|
||||
|
||||
#include <Nazara/Platform/VideoMode.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class VideoModeImpl
|
||||
{
|
||||
public:
|
||||
static VideoMode GetDesktopMode();
|
||||
static void GetFullscreenModes(std::vector<VideoMode>& modes);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NNAZARA_VIDEOMODEIMPL_HPP
|
||||
1170
src/Nazara/Platform/Win32/WindowImpl.cpp
Normal file
1170
src/Nazara/Platform/Win32/WindowImpl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
114
src/Nazara/Platform/Win32/WindowImpl.hpp
Normal file
114
src/Nazara/Platform/Win32/WindowImpl.hpp
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// Interface inspirée de la SFML par Laurent Gomila
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_WINDOWIMPL_HPP
|
||||
#define NAZARA_WINDOWIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <Nazara/Core/Thread.hpp>
|
||||
#include <Nazara/Math/Rect.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Platform/Config.hpp>
|
||||
#include <Nazara/Platform/Keyboard.hpp>
|
||||
#include <Nazara/Platform/Mouse.hpp>
|
||||
#include <Nazara/Platform/VideoMode.hpp>
|
||||
#include <Nazara/Platform/Window.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class ConditionVariable;
|
||||
class Mutex;
|
||||
class Window;
|
||||
|
||||
#undef IsMinimized // Conflits with windows.h redefinition
|
||||
|
||||
class WindowImpl
|
||||
{
|
||||
public:
|
||||
WindowImpl(Window* parent);
|
||||
WindowImpl(const WindowImpl&) = delete;
|
||||
WindowImpl(WindowImpl&&) = delete; ///TODO?
|
||||
~WindowImpl() = default;
|
||||
|
||||
bool Create(const VideoMode& mode, const String& title, WindowStyleFlags style);
|
||||
bool Create(WindowHandle handle);
|
||||
|
||||
void Destroy();
|
||||
|
||||
void EnableKeyRepeat(bool enable);
|
||||
void EnableSmoothScrolling(bool enable);
|
||||
|
||||
WindowHandle GetHandle() const;
|
||||
unsigned int GetHeight() const;
|
||||
Vector2i GetPosition() const;
|
||||
Vector2ui GetSize() const;
|
||||
WindowStyleFlags GetStyle() const;
|
||||
String GetTitle() const;
|
||||
unsigned int GetWidth() const;
|
||||
|
||||
bool HasFocus() const;
|
||||
|
||||
void IgnoreNextMouseEvent(int mouseX, int mouseY);
|
||||
|
||||
bool IsMinimized() const;
|
||||
bool IsVisible() const;
|
||||
|
||||
void ProcessEvents(bool block);
|
||||
|
||||
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);
|
||||
|
||||
WindowImpl& operator=(const WindowImpl&) = delete;
|
||||
WindowImpl& operator=(WindowImpl&&) = delete; ///TODO?
|
||||
|
||||
static bool Initialize();
|
||||
static void Uninitialize();
|
||||
|
||||
private:
|
||||
bool HandleMessage(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void PrepareWindow(bool fullscreen);
|
||||
|
||||
static Keyboard::Key ConvertVirtualKey(WPARAM key, LPARAM flags);
|
||||
static LRESULT CALLBACK MessageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
static UInt32 RetrieveStyle(HWND window);
|
||||
static void WindowThread(HWND* handle, DWORD styleEx, const String& title, DWORD style, bool fullscreen, const Rectui& dimensions, WindowImpl* window, Mutex* mutex, ConditionVariable* condition);
|
||||
|
||||
HCURSOR m_cursor;
|
||||
HWND m_handle;
|
||||
LONG_PTR m_callback;
|
||||
WindowStyleFlags m_style;
|
||||
Vector2i m_maxSize;
|
||||
Vector2i m_minSize;
|
||||
Vector2i m_mousePos;
|
||||
Vector2i m_position;
|
||||
Vector2ui m_size;
|
||||
Thread m_thread;
|
||||
Window* m_parent;
|
||||
bool m_eventListener;
|
||||
bool m_keyRepeat;
|
||||
bool m_mouseInside;
|
||||
bool m_ownsWindow;
|
||||
bool m_sizemove;
|
||||
bool m_smoothScrolling;
|
||||
bool m_threadActive;
|
||||
short m_scrolling;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_WINDOWIMPL_HPP
|
||||
649
src/Nazara/Platform/Window.cpp
Normal file
649
src/Nazara/Platform/Window.cpp
Normal file
@@ -0,0 +1,649 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/Window.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/LockGuard.hpp>
|
||||
#include <Nazara/Platform/Cursor.hpp>
|
||||
#include <Nazara/Platform/Icon.hpp>
|
||||
#include <Nazara/Utility/Image.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Platform/Win32/WindowImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_X11)
|
||||
#include <Nazara/Platform/X11/WindowImpl.hpp>
|
||||
#else
|
||||
#error Lack of implementation: Window
|
||||
#endif
|
||||
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
Window* fullscreenWindow = nullptr;
|
||||
}
|
||||
|
||||
Window::Window() :
|
||||
m_impl(nullptr),
|
||||
m_asyncWindow(false),
|
||||
m_closeOnQuit(true),
|
||||
m_eventPolling(false),
|
||||
m_waitForEvent(false)
|
||||
{
|
||||
m_cursorController.OnCursorUpdated.Connect([this](const CursorController*, const CursorRef& cursor)
|
||||
{
|
||||
if (IsValid())
|
||||
SetCursor(cursor);
|
||||
});
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool Window::Create(VideoMode mode, const String& title, WindowStyleFlags style)
|
||||
{
|
||||
// If the window is already open, we keep its position
|
||||
bool opened = IsOpen();
|
||||
Vector2i position;
|
||||
if (opened)
|
||||
position = m_impl->GetPosition();
|
||||
|
||||
Destroy();
|
||||
|
||||
// Inspired by the code of the SFML by Laurent Gomila (and its team)
|
||||
if (style & WindowStyle_Fullscreen)
|
||||
{
|
||||
if (fullscreenWindow)
|
||||
{
|
||||
NazaraError("Window " + String::Pointer(fullscreenWindow) + " already in fullscreen mode");
|
||||
style &= ~WindowStyle_Fullscreen;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mode.IsFullscreenValid())
|
||||
{
|
||||
NazaraWarning("Video mode is not fullscreen valid");
|
||||
mode = VideoMode::GetFullscreenModes()[0];
|
||||
}
|
||||
|
||||
fullscreenWindow = this;
|
||||
}
|
||||
}
|
||||
else if (style & WindowStyle_Closable || style & WindowStyle_Resizable)
|
||||
style |= WindowStyle_Titlebar;
|
||||
|
||||
m_asyncWindow = (style & WindowStyle_Threaded) != 0;
|
||||
|
||||
std::unique_ptr<WindowImpl> impl = std::make_unique<WindowImpl>(this);
|
||||
if (!impl->Create(mode, title, style))
|
||||
{
|
||||
NazaraError("Failed to create window implementation");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl.release();
|
||||
CallOnExit destroyOnFailure([this] () { Destroy(); });
|
||||
|
||||
m_closed = false;
|
||||
m_ownsWindow = true;
|
||||
|
||||
if (!OnWindowCreated())
|
||||
{
|
||||
NazaraError("Failed to initialize window extension");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Default parameters
|
||||
m_impl->EnableKeyRepeat(true);
|
||||
m_impl->EnableSmoothScrolling(false);
|
||||
m_impl->SetMaximumSize(-1, -1);
|
||||
m_impl->SetMinimumSize(-1, -1);
|
||||
m_impl->SetVisible(true);
|
||||
|
||||
SetCursor(Cursor::Get(SystemCursor_Default));
|
||||
|
||||
if (opened)
|
||||
m_impl->SetPosition(position.x, position.y);
|
||||
|
||||
OnWindowResized();
|
||||
|
||||
destroyOnFailure.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Window::Create(WindowHandle handle)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_asyncWindow = false;
|
||||
m_impl = new WindowImpl(this);
|
||||
if (!m_impl->Create(handle))
|
||||
{
|
||||
NazaraError("Unable to create window implementation");
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_closed = false;
|
||||
m_ownsWindow = false;
|
||||
|
||||
if (!OnWindowCreated())
|
||||
{
|
||||
NazaraError("Failed to initialize window's derivate");
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window::Destroy()
|
||||
{
|
||||
m_cursor.Reset();
|
||||
|
||||
if (m_impl)
|
||||
{
|
||||
OnWindowDestroy();
|
||||
|
||||
m_impl->Destroy();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
|
||||
if (fullscreenWindow == this)
|
||||
fullscreenWindow = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Window::EnableKeyRepeat(bool enable)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->EnableKeyRepeat(enable);
|
||||
}
|
||||
|
||||
void Window::EnableSmoothScrolling(bool enable)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->EnableSmoothScrolling(enable);
|
||||
}
|
||||
|
||||
WindowHandle Window::GetHandle() const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return static_cast<WindowHandle>(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetHandle();
|
||||
}
|
||||
|
||||
unsigned int Window::GetHeight() const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetHeight();
|
||||
}
|
||||
|
||||
Vector2i Window::GetPosition() const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return Vector2i::Zero();
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetPosition();
|
||||
}
|
||||
|
||||
Vector2ui Window::GetSize() const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return Vector2ui::Zero();
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetSize();
|
||||
}
|
||||
|
||||
WindowStyleFlags Window::GetStyle() const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetStyle();
|
||||
}
|
||||
|
||||
String Window::GetTitle() const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return String();
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetTitle();
|
||||
}
|
||||
|
||||
unsigned int Window::GetWidth() const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetWidth();
|
||||
}
|
||||
|
||||
bool Window::HasFocus() const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->HasFocus();
|
||||
}
|
||||
|
||||
bool Window::IsMinimized() const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->IsMinimized();
|
||||
}
|
||||
|
||||
bool Window::IsVisible() const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->IsVisible();
|
||||
}
|
||||
|
||||
bool Window::PollEvent(WindowEvent* event)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_asyncWindow)
|
||||
m_impl->ProcessEvents(false);
|
||||
|
||||
if (!m_events.empty())
|
||||
{
|
||||
if (event)
|
||||
*event = m_events.front();
|
||||
|
||||
m_events.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Window::ProcessEvents(bool block)
|
||||
{
|
||||
NazaraAssert(m_impl, "Window not created");
|
||||
NazaraUnused(block);
|
||||
|
||||
if (!m_asyncWindow)
|
||||
m_impl->ProcessEvents(block);
|
||||
else
|
||||
{
|
||||
LockGuard eventLock(m_eventMutex);
|
||||
|
||||
for (const WindowEvent& event : m_pendingEvents)
|
||||
HandleEvent(event);
|
||||
|
||||
m_pendingEvents.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::SetCursor(CursorRef cursor)
|
||||
{
|
||||
NazaraAssert(m_impl, "Window not created");
|
||||
NazaraAssert(cursor && cursor->IsValid(), "Invalid cursor");
|
||||
|
||||
m_cursor = std::move(cursor);
|
||||
m_impl->SetCursor(*m_cursor);
|
||||
}
|
||||
|
||||
void Window::SetEventListener(bool listener)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetEventListener(listener);
|
||||
if (!listener)
|
||||
{
|
||||
// Empty the event queue
|
||||
while (!m_events.empty())
|
||||
m_events.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::SetFocus()
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetFocus();
|
||||
}
|
||||
|
||||
void Window::SetIcon(IconRef icon)
|
||||
{
|
||||
NazaraAssert(m_impl, "Window not created");
|
||||
NazaraAssert(icon && icon.IsValid(), "Invalid icon");
|
||||
|
||||
m_icon = std::move(icon);
|
||||
m_impl->SetIcon(*m_icon);
|
||||
}
|
||||
|
||||
void Window::SetMaximumSize(const Vector2i& maxSize)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetMaximumSize(maxSize.x, maxSize.y);
|
||||
}
|
||||
|
||||
void Window::SetMaximumSize(int width, int height)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetMaximumSize(width, height);
|
||||
}
|
||||
|
||||
void Window::SetMinimumSize(const Vector2i& minSize)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetMinimumSize(minSize.x, minSize.y);
|
||||
}
|
||||
|
||||
void Window::SetMinimumSize(int width, int height)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetMinimumSize(width, height);
|
||||
}
|
||||
|
||||
void Window::SetPosition(const Vector2i& position)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetPosition(position.x, position.y);
|
||||
}
|
||||
|
||||
void Window::SetPosition(int x, int y)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetPosition(x, y);
|
||||
}
|
||||
|
||||
void Window::SetSize(const Vector2i& size)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetSize(size.x, size.y);
|
||||
}
|
||||
|
||||
void Window::SetSize(unsigned int width, unsigned int height)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetSize(width, height);
|
||||
}
|
||||
|
||||
void Window::SetStayOnTop(bool stayOnTop)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetStayOnTop(stayOnTop);
|
||||
}
|
||||
|
||||
void Window::SetTitle(const String& title)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetTitle(title);
|
||||
}
|
||||
|
||||
void Window::SetVisible(bool visible)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SetVisible(visible);
|
||||
}
|
||||
|
||||
bool Window::WaitEvent(WindowEvent* event)
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_asyncWindow)
|
||||
{
|
||||
while (m_events.empty())
|
||||
m_impl->ProcessEvents(true);
|
||||
|
||||
if (event)
|
||||
*event = m_events.front();
|
||||
|
||||
m_events.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LockGuard lock(m_eventMutex);
|
||||
|
||||
if (m_events.empty())
|
||||
{
|
||||
m_waitForEvent = true;
|
||||
m_eventConditionMutex.Lock();
|
||||
m_eventMutex.Unlock();
|
||||
m_eventCondition.Wait(&m_eventConditionMutex);
|
||||
m_eventMutex.Lock();
|
||||
m_eventConditionMutex.Unlock();
|
||||
m_waitForEvent = false;
|
||||
}
|
||||
|
||||
if (!m_events.empty())
|
||||
{
|
||||
if (event)
|
||||
*event = m_events.front();
|
||||
|
||||
m_events.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Window::OnWindowCreated()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window::OnWindowDestroy()
|
||||
{
|
||||
}
|
||||
|
||||
void Window::OnWindowResized()
|
||||
{
|
||||
}
|
||||
|
||||
void Window::IgnoreNextMouseEvent(int mouseX, int mouseY) const
|
||||
{
|
||||
#if NAZARA_PLATFORM_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Window not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->IgnoreNextMouseEvent(mouseX, mouseY);
|
||||
}
|
||||
|
||||
bool Window::Initialize()
|
||||
{
|
||||
return WindowImpl::Initialize();
|
||||
}
|
||||
|
||||
void Window::Uninitialize()
|
||||
{
|
||||
WindowImpl::Uninitialize();
|
||||
}
|
||||
}
|
||||
270
src/Nazara/Platform/X11/CursorImpl.cpp
Normal file
270
src/Nazara/Platform/X11/CursorImpl.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/X11/CursorImpl.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Utility/Image.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/Platform/X11/Display.hpp>
|
||||
#include <xcb/xcb_image.h>
|
||||
|
||||
// Some older versions of xcb/util-renderutil (notably the one available on Travis CI) use `template` as an argument name
|
||||
// This is a fixed bug (https://cgit.freedesktop.org/xcb/util-renderutil/commit/?id=8d15acc45a47dc4c922eee5b99885db42bc62c17) but until Travis-CI
|
||||
// has upgraded their Ubuntu version, I'm forced to use this ugly trick.
|
||||
#define template ptemplate
|
||||
extern "C"
|
||||
{
|
||||
#include <xcb/xcb_renderutil.h>
|
||||
}
|
||||
#undef template
|
||||
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool CursorImpl::Create(const Image& cursor, int hotSpotX, int hotSpotY)
|
||||
{
|
||||
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();
|
||||
|
||||
ScopedXCBConnection connection;
|
||||
|
||||
xcb_screen_t* screen = X11::XCBDefaultScreen(connection);
|
||||
|
||||
ScopedXCB<xcb_generic_error_t> error(nullptr);
|
||||
ScopedXCB<xcb_render_query_pict_formats_reply_t> 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<uint8_t[]> 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,
|
||||
xcb_render_create_picture(
|
||||
connection,
|
||||
pic,
|
||||
pix,
|
||||
fmt->id,
|
||||
0,
|
||||
nullptr
|
||||
)))
|
||||
{
|
||||
NazaraError("Failed to create render picture for cursor");
|
||||
return false;
|
||||
}
|
||||
|
||||
XCBGContext gc(connection);
|
||||
if (!gc.Create(pix, 0, nullptr))
|
||||
{
|
||||
NazaraError("Failed to create gcontext for cursor");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!X11::CheckCookie(
|
||||
connection,
|
||||
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;
|
||||
}
|
||||
|
||||
bool CursorImpl::Create(SystemCursor cursor)
|
||||
{
|
||||
ScopedXCBConnection connection;
|
||||
xcb_screen_t* screen = X11::XCBDefaultScreen(connection);
|
||||
|
||||
const char* cursorName = s_systemCursorIds[cursor];
|
||||
if (cursorName)
|
||||
{
|
||||
if (xcb_cursor_context_new(connection, screen, &m_cursorContext) >= 0)
|
||||
m_cursor = xcb_cursor_load_cursor(m_cursorContext, cursorName);
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to create cursor context");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_cursor = s_hiddenCursor;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CursorImpl::Destroy()
|
||||
{
|
||||
ScopedXCBConnection connection;
|
||||
|
||||
xcb_free_cursor(connection, m_cursor);
|
||||
if (m_cursorContext)
|
||||
xcb_cursor_context_free(m_cursorContext);
|
||||
}
|
||||
|
||||
xcb_cursor_t CursorImpl::GetCursor()
|
||||
{
|
||||
return m_cursor;
|
||||
}
|
||||
|
||||
bool CursorImpl::Initialize()
|
||||
{
|
||||
ScopedXCBConnection connection;
|
||||
XCBPixmap cursorPixmap(connection);
|
||||
|
||||
xcb_window_t window = X11::XCBDefaultRootWindow(connection);
|
||||
|
||||
if (!cursorPixmap.Create(1, window, 1, 1))
|
||||
{
|
||||
NazaraError("Failed to create pixmap for hidden cursor");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_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_create_cursor(connection,
|
||||
s_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");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CursorImpl::Uninitialize()
|
||||
{
|
||||
if (s_hiddenCursor)
|
||||
{
|
||||
ScopedXCBConnection connection;
|
||||
xcb_free_cursor(connection, s_hiddenCursor);
|
||||
s_hiddenCursor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
xcb_cursor_t CursorImpl::s_hiddenCursor = 0;
|
||||
|
||||
std::array<const char*, SystemCursor_Max + 1> CursorImpl::s_systemCursorIds =
|
||||
{
|
||||
{
|
||||
// http://gnome-look.org/content/preview.php?preview=1&id=128170&file1=128170-1.png&file2=&file3=&name=Dummy+X11+cursors&PHPSESSID=6
|
||||
"crosshair", // SystemCursor_Crosshair
|
||||
"left_ptr", // SystemCursor_Default
|
||||
"hand", // SystemCursor_Hand
|
||||
"help", // SystemCursor_Help
|
||||
"fleur", // SystemCursor_Move
|
||||
nullptr, // SystemCursor_None
|
||||
"hand", // SystemCursor_Pointer
|
||||
"watch", // SystemCursor_Progress
|
||||
"right_side", // SystemCursor_ResizeE
|
||||
"top_side", // SystemCursor_ResizeN
|
||||
"top_right_corner", // SystemCursor_ResizeNE
|
||||
"top_left_corner", // SystemCursor_ResizeNW
|
||||
"bottom_side", // SystemCursor_ResizeS
|
||||
"bottom_right_corner", // SystemCursor_ResizeSE
|
||||
"bottom_left_corner", // SystemCursor_ResizeSW
|
||||
"left_side", // SystemCursor_ResizeW
|
||||
"xterm", // SystemCursor_Text
|
||||
"watch" // SystemCursor_Wait
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(SystemCursor_Max + 1 == 18, "System cursor array is incomplete");
|
||||
}
|
||||
43
src/Nazara/Platform/X11/CursorImpl.hpp
Normal file
43
src/Nazara/Platform/X11/CursorImpl.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_CURSORIMPL_HPP
|
||||
#define NAZARA_CURSORIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Platform/Enums.hpp>
|
||||
#include <xcb/xcb_cursor.h>
|
||||
#include <array>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class Image;
|
||||
|
||||
class CursorImpl
|
||||
{
|
||||
friend class Cursor;
|
||||
|
||||
public:
|
||||
bool Create(const Image& image, int hotSpotX, int hotSpotY);
|
||||
bool Create(SystemCursor cursor);
|
||||
|
||||
void Destroy();
|
||||
|
||||
xcb_cursor_t GetCursor();
|
||||
|
||||
private:
|
||||
static bool Initialize();
|
||||
static void Uninitialize();
|
||||
|
||||
xcb_cursor_t m_cursor = 0;
|
||||
xcb_cursor_context_t* m_cursorContext = nullptr;
|
||||
|
||||
static xcb_cursor_t s_hiddenCursor;
|
||||
static std::array<const char*, SystemCursor_Max + 1> s_systemCursorIds;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_CURSORIMPL_HPP
|
||||
247
src/Nazara/Platform/X11/Display.cpp
Normal file
247
src/Nazara/Platform/X11/Display.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/X11/Display.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <xcb/xcb_keysyms.h>
|
||||
#include <map>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// 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<String, xcb_atom_t>;
|
||||
AtomMap atoms;
|
||||
}
|
||||
|
||||
bool X11::CheckCookie(xcb_connection_t* connection, xcb_void_cookie_t cookie)
|
||||
{
|
||||
ScopedXCB<xcb_generic_error_t> error(xcb_request_check(
|
||||
connection,
|
||||
cookie
|
||||
));
|
||||
|
||||
if (error)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
void X11::CloseConnection(xcb_connection_t* connection)
|
||||
{
|
||||
NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server");
|
||||
--referenceCountConnection;
|
||||
}
|
||||
|
||||
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 X11::GetAtom(const String& name, bool onlyIfExists)
|
||||
{
|
||||
AtomMap::const_iterator iter = atoms.find(name);
|
||||
|
||||
if (iter != atoms.end())
|
||||
return iter->second;
|
||||
|
||||
ScopedXCB<xcb_generic_error_t> error(nullptr);
|
||||
|
||||
xcb_connection_t* connection = OpenConnection();
|
||||
|
||||
ScopedXCB<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(
|
||||
connection,
|
||||
xcb_intern_atom(
|
||||
connection,
|
||||
onlyIfExists,
|
||||
name.GetSize(),
|
||||
name.GetConstBuffer()
|
||||
),
|
||||
&error
|
||||
));
|
||||
|
||||
CloseConnection(connection);
|
||||
|
||||
if (error || !reply)
|
||||
{
|
||||
NazaraError("Failed to get " + name + " atom.");
|
||||
return XCB_ATOM_NONE;
|
||||
}
|
||||
|
||||
atoms[name] = reply->atom;
|
||||
|
||||
return reply->atom;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
{
|
||||
sharedConnection = xcb_connect(nullptr, &screen_nbr);
|
||||
|
||||
// Opening display failed: The best we can do at the moment is to output a meaningful error message
|
||||
if (!sharedConnection || xcb_connection_has_error(sharedConnection))
|
||||
{
|
||||
NazaraError("Failed to open xcb connection");
|
||||
return false;
|
||||
}
|
||||
|
||||
OpenConnection();
|
||||
}
|
||||
|
||||
{
|
||||
sharedkeySymbol = xcb_key_symbols_alloc(sharedConnection);
|
||||
|
||||
XCBKeySymbolsAlloc(sharedConnection);
|
||||
}
|
||||
|
||||
{
|
||||
sharedEwmhConnection = new xcb_ewmh_connection_t;
|
||||
xcb_intern_atom_cookie_t* ewmh_cookie = xcb_ewmh_init_atoms(sharedConnection, sharedEwmhConnection);
|
||||
|
||||
if(!xcb_ewmh_init_atoms_replies(sharedEwmhConnection, ewmh_cookie, nullptr))
|
||||
{
|
||||
NazaraError("Could not initialize EWMH Connection");
|
||||
sharedEwmhConnection = nullptr;
|
||||
}
|
||||
|
||||
OpenEWMHConnection(sharedConnection);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
++referenceCountKeySymbol;
|
||||
return sharedkeySymbol;
|
||||
}
|
||||
|
||||
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* X11::OpenConnection()
|
||||
{
|
||||
++referenceCountConnection;
|
||||
return sharedConnection;
|
||||
}
|
||||
|
||||
xcb_ewmh_connection_t* X11::OpenEWMHConnection(xcb_connection_t* connection)
|
||||
{
|
||||
NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server");
|
||||
|
||||
++referenceCountEwmhConnection;
|
||||
return sharedEwmhConnection;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
xcb_ewmh_connection_wipe(sharedEwmhConnection);
|
||||
delete sharedEwmhConnection;
|
||||
}
|
||||
|
||||
{
|
||||
NazaraAssert(referenceCountKeySymbol == 1, "Uninitialize should be called after anything or a free is missing");
|
||||
XCBKeySymbolsFree(sharedkeySymbol);
|
||||
|
||||
xcb_key_symbols_free(sharedkeySymbol);
|
||||
}
|
||||
|
||||
{
|
||||
NazaraAssert(referenceCountConnection == 1, "Uninitialize should be called after anything or a close is missing");
|
||||
CloseConnection(sharedConnection);
|
||||
|
||||
xcb_disconnect(sharedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (screen)
|
||||
return screen->root;
|
||||
return XCB_NONE;
|
||||
}
|
||||
|
||||
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 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* X11::XCBScreenOfDisplay(xcb_connection_t* connection, int screenIndex)
|
||||
{
|
||||
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));
|
||||
|
||||
for (; iter.rem; --screenIndex, xcb_screen_next (&iter))
|
||||
{
|
||||
if (screenIndex == 0)
|
||||
return iter.data;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int X11::s_moduleReferenceCounter = 0;
|
||||
}
|
||||
53
src/Nazara/Platform/X11/Display.hpp
Normal file
53
src/Nazara/Platform/X11/Display.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_X11DISPLAY_HPP
|
||||
#define NAZARA_X11DISPLAY_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Platform/WindowHandle.hpp>
|
||||
#include <Nazara/Platform/X11/ScopedXCB.hpp>
|
||||
|
||||
typedef struct _XCBKeySymbols xcb_key_symbols_t;
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class String;
|
||||
|
||||
class NAZARA_PLATFORM_API X11
|
||||
{
|
||||
public:
|
||||
X11() = delete;
|
||||
~X11() = delete;
|
||||
|
||||
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);
|
||||
|
||||
static xcb_atom_t GetAtom(const String& name, bool onlyIfExists = false);
|
||||
|
||||
static bool Initialize();
|
||||
static bool IsInitialized();
|
||||
|
||||
static xcb_key_symbols_t* XCBKeySymbolsAlloc(xcb_connection_t* connection);
|
||||
static void XCBKeySymbolsFree(xcb_key_symbols_t* keySymbols);
|
||||
|
||||
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
|
||||
137
src/Nazara/Platform/X11/IconImpl.cpp
Normal file
137
src/Nazara/Platform/X11/IconImpl.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/X11/IconImpl.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Utility/Image.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/Platform/X11/Display.hpp>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
IconImpl::IconImpl()
|
||||
{
|
||||
ScopedXCBConnection connection;
|
||||
|
||||
m_iconPixmap.Connect(connection);
|
||||
m_maskPixmap.Connect(connection);
|
||||
}
|
||||
|
||||
bool IconImpl::Create(const Image& icon)
|
||||
{
|
||||
Image iconImage(icon); // Vive le COW
|
||||
if (!iconImage.Convert(Nz::PixelFormatType_BGRA8))
|
||||
{
|
||||
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<UInt8> maskPixels(pitch * height, 0);
|
||||
for (std::size_t j = 0; j < height; ++j)
|
||||
{
|
||||
for (std::size_t i = 0; i < pitch; ++i)
|
||||
{
|
||||
for (std::size_t k = 0; k < 8; ++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<uint8_t*>(&maskPixels[0]),
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
nullptr))
|
||||
{
|
||||
NazaraError("Failed to create mask pixmap for icon");
|
||||
return false;
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IconImpl::Destroy()
|
||||
{
|
||||
m_iconPixmap.Destroy();
|
||||
m_maskPixmap.Destroy();
|
||||
}
|
||||
|
||||
xcb_pixmap_t IconImpl::GetIcon()
|
||||
{
|
||||
return m_iconPixmap;
|
||||
}
|
||||
|
||||
xcb_pixmap_t IconImpl::GetMask()
|
||||
{
|
||||
return m_maskPixmap;
|
||||
}
|
||||
}
|
||||
34
src/Nazara/Platform/X11/IconImpl.hpp
Normal file
34
src/Nazara/Platform/X11/IconImpl.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_ICONIMPL_HPP
|
||||
#define NAZARA_ICONIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Platform/X11/ScopedXCB.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class Image;
|
||||
|
||||
class IconImpl
|
||||
{
|
||||
public:
|
||||
IconImpl();
|
||||
|
||||
bool Create(const Image& image);
|
||||
void Destroy();
|
||||
|
||||
xcb_pixmap_t GetIcon();
|
||||
xcb_pixmap_t GetMask();
|
||||
|
||||
private:
|
||||
XCBPixmap m_iconPixmap;
|
||||
XCBPixmap m_maskPixmap;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_ICONIMPL_HPP
|
||||
389
src/Nazara/Platform/X11/InputImpl.cpp
Normal file
389
src/Nazara/Platform/X11/InputImpl.cpp
Normal file
@@ -0,0 +1,389 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/X11/InputImpl.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Platform/Window.hpp>
|
||||
#include <Nazara/Platform/X11/Display.hpp>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/XF86keysym.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <xcb/xcb_keysyms.h>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
KeySym GetKeySym(Keyboard::Key key)
|
||||
{
|
||||
// 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 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 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 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 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 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 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 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 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;
|
||||
}
|
||||
|
||||
// Sanity checks
|
||||
if (key < 0 || key >= Keyboard::Count || keysym == 0)
|
||||
NazaraWarning("Key " + String::Number(key) + " is not handled in Keyboard");
|
||||
|
||||
return keysym;
|
||||
}
|
||||
}
|
||||
|
||||
String EventImpl::GetKeyName(Keyboard::Key key)
|
||||
{
|
||||
KeySym keySym = GetKeySym(key);
|
||||
|
||||
// XKeysymToString returns a static area.
|
||||
return XKeysymToString(keySym);
|
||||
}
|
||||
|
||||
Vector2i EventImpl::GetMousePosition()
|
||||
{
|
||||
ScopedXCBConnection connection;
|
||||
|
||||
ScopedXCB<xcb_generic_error_t> error(nullptr);
|
||||
|
||||
ScopedXCB<xcb_query_pointer_reply_t> pointer(
|
||||
xcb_query_pointer_reply(
|
||||
connection,
|
||||
xcb_query_pointer(
|
||||
connection,
|
||||
X11::XCBDefaultRootWindow(connection)
|
||||
),
|
||||
&error
|
||||
)
|
||||
);
|
||||
|
||||
if (error)
|
||||
{
|
||||
NazaraError("Failed to query pointer");
|
||||
return Vector2i(-1, -1);
|
||||
}
|
||||
|
||||
return Vector2i(pointer->root_x, pointer->root_y);
|
||||
}
|
||||
|
||||
Vector2i EventImpl::GetMousePosition(const Window& relativeTo)
|
||||
{
|
||||
WindowHandle handle = relativeTo.GetHandle();
|
||||
if (handle)
|
||||
{
|
||||
// Open a connection with the X server
|
||||
ScopedXCBConnection connection;
|
||||
|
||||
ScopedXCB<xcb_generic_error_t> error(nullptr);
|
||||
|
||||
ScopedXCB<xcb_query_pointer_reply_t> 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 EventImpl::IsKeyPressed(Keyboard::Key key)
|
||||
{
|
||||
ScopedXCBConnection connection;
|
||||
|
||||
xcb_keysym_t keySym = GetKeySym(key);
|
||||
|
||||
xcb_keycode_t realKeyCode = XCB_NO_SYMBOL;
|
||||
|
||||
xcb_key_symbols_t* keySymbols = X11::XCBKeySymbolsAlloc(connection);
|
||||
if (!keySymbols)
|
||||
{
|
||||
NazaraError("Failed to alloc key symbols");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedXCB<xcb_keycode_t> keyCode = xcb_key_symbols_get_keycode(keySymbols, keySym);
|
||||
if (!keyCode)
|
||||
{
|
||||
NazaraError("Failed to get key code");
|
||||
return false;
|
||||
}
|
||||
|
||||
// One keysym is associated with multiple key codes, we have to find the matching one ...
|
||||
int i = 0;
|
||||
while (keyCode.get()[i] != XCB_NO_SYMBOL)
|
||||
{
|
||||
xcb_keycode_t toTry = keyCode.get()[i];
|
||||
if (keySym == xcb_key_symbols_get_keysym(keySymbols, toTry, 0))
|
||||
{
|
||||
realKeyCode = toTry;
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
X11::XCBKeySymbolsFree(keySymbols);
|
||||
|
||||
ScopedXCB<xcb_generic_error_t> error(nullptr);
|
||||
|
||||
// Get the whole keyboard state
|
||||
ScopedXCB<xcb_query_keymap_reply_t> keymap(
|
||||
xcb_query_keymap_reply(
|
||||
connection,
|
||||
xcb_query_keymap(connection),
|
||||
&error
|
||||
)
|
||||
);
|
||||
|
||||
if (error)
|
||||
{
|
||||
NazaraError("Failed to query keymap");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check our keycode
|
||||
return (keymap->keys[realKeyCode / 8] & (1 << (realKeyCode % 8))) != 0;
|
||||
}
|
||||
|
||||
bool EventImpl::IsMouseButtonPressed(Mouse::Button button)
|
||||
{
|
||||
ScopedXCBConnection connection;
|
||||
|
||||
ScopedXCB<xcb_generic_error_t> error(nullptr);
|
||||
|
||||
// Get pointer mask
|
||||
ScopedXCB<xcb_query_pointer_reply_t> 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;
|
||||
}
|
||||
|
||||
void EventImpl::SetMousePosition(int x, int y)
|
||||
{
|
||||
ScopedXCBConnection 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 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");
|
||||
}
|
||||
}
|
||||
31
src/Nazara/Platform/X11/InputImpl.hpp
Normal file
31
src/Nazara/Platform/X11/InputImpl.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_INPUTIMPL_HPP
|
||||
#define NAZARA_INPUTIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Platform/Keyboard.hpp>
|
||||
#include <Nazara/Platform/Mouse.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
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
|
||||
199
src/Nazara/Platform/X11/ScopedXCB.cpp
Normal file
199
src/Nazara/Platform/X11/ScopedXCB.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/X11/ScopedXCB.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Platform/X11/Display.hpp>
|
||||
#include <xcb/xcb_image.h>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/***********************************************
|
||||
ScopedXCBConnection
|
||||
***********************************************/
|
||||
|
||||
ScopedXCBConnection::ScopedXCBConnection() :
|
||||
m_connection(nullptr)
|
||||
{
|
||||
m_connection = X11::OpenConnection();
|
||||
}
|
||||
|
||||
ScopedXCBConnection::~ScopedXCBConnection()
|
||||
{
|
||||
X11::CloseConnection(m_connection);
|
||||
}
|
||||
|
||||
ScopedXCBConnection::operator xcb_connection_t*() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
ScopedXCBEWMHConnection
|
||||
***********************************************/
|
||||
|
||||
ScopedXCBEWMHConnection::ScopedXCBEWMHConnection(xcb_connection_t* connection) :
|
||||
m_ewmhConnection(nullptr)
|
||||
{
|
||||
m_ewmhConnection = X11::OpenEWMHConnection(connection);
|
||||
}
|
||||
|
||||
ScopedXCBEWMHConnection::~ScopedXCBEWMHConnection()
|
||||
{
|
||||
X11::CloseEWMHConnection(m_ewmhConnection);
|
||||
}
|
||||
|
||||
xcb_ewmh_connection_t* ScopedXCBEWMHConnection::operator ->() const
|
||||
{
|
||||
return m_ewmhConnection;
|
||||
}
|
||||
|
||||
ScopedXCBEWMHConnection::operator xcb_ewmh_connection_t*() const
|
||||
{
|
||||
return m_ewmhConnection;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
XCBGContext
|
||||
***********************************************/
|
||||
|
||||
XCBGContext::XCBGContext(xcb_connection_t* connection) :
|
||||
m_connection(connection),
|
||||
m_gcontext(XCB_NONE)
|
||||
{
|
||||
NazaraAssert(connection, "Connection must have been established");
|
||||
}
|
||||
|
||||
XCBGContext::~XCBGContext()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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,
|
||||
drawable,
|
||||
data,
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
fg,
|
||||
bg,
|
||||
gcp
|
||||
);
|
||||
|
||||
return m_pixmap != XCB_NONE;
|
||||
}
|
||||
|
||||
void XCBPixmap::Destroy()
|
||||
{
|
||||
if (m_pixmap == XCB_NONE)
|
||||
return;
|
||||
|
||||
if (!X11::CheckCookie(
|
||||
m_connection,
|
||||
xcb_free_pixmap(
|
||||
m_connection,
|
||||
m_pixmap
|
||||
))
|
||||
)
|
||||
NazaraError("Failed to free pixmap");
|
||||
|
||||
m_pixmap = XCB_NONE;
|
||||
}
|
||||
|
||||
XCBPixmap::operator xcb_pixmap_t() const
|
||||
{
|
||||
return m_pixmap;
|
||||
}
|
||||
}
|
||||
100
src/Nazara/Platform/X11/ScopedXCB.hpp
Normal file
100
src/Nazara/Platform/X11/ScopedXCB.hpp
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SCOPEDXCB_HPP
|
||||
#define NAZARA_SCOPEDXCB_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_ewmh.h>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class ScopedXCBConnection
|
||||
{
|
||||
public:
|
||||
ScopedXCBConnection();
|
||||
~ScopedXCBConnection();
|
||||
|
||||
operator xcb_connection_t*() const;
|
||||
|
||||
private:
|
||||
xcb_connection_t* m_connection;
|
||||
};
|
||||
|
||||
class ScopedXCBEWMHConnection
|
||||
{
|
||||
public:
|
||||
ScopedXCBEWMHConnection(xcb_connection_t* connection);
|
||||
~ScopedXCBEWMHConnection();
|
||||
|
||||
xcb_ewmh_connection_t* operator ->() const;
|
||||
|
||||
operator xcb_ewmh_connection_t*() const;
|
||||
|
||||
private:
|
||||
xcb_ewmh_connection_t* m_ewmhConnection;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ScopedXCB
|
||||
{
|
||||
public:
|
||||
ScopedXCB(T* pointer);
|
||||
~ScopedXCB();
|
||||
|
||||
T* operator ->() const;
|
||||
T** operator &();
|
||||
|
||||
operator bool() const;
|
||||
|
||||
T* get() const;
|
||||
|
||||
private:
|
||||
T* m_pointer;
|
||||
};
|
||||
|
||||
class XCBGContext
|
||||
{
|
||||
public:
|
||||
XCBGContext(xcb_connection_t* connection);
|
||||
~XCBGContext();
|
||||
|
||||
bool Create(xcb_drawable_t drawable, uint32_t value_mask, const uint32_t* value_list);
|
||||
|
||||
void Destroy();
|
||||
|
||||
operator xcb_gcontext_t() const;
|
||||
|
||||
private:
|
||||
xcb_connection_t* m_connection;
|
||||
xcb_gcontext_t m_gcontext;
|
||||
};
|
||||
|
||||
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 Destroy();
|
||||
|
||||
operator xcb_pixmap_t() const;
|
||||
|
||||
private:
|
||||
xcb_connection_t* m_connection;
|
||||
xcb_pixmap_t m_pixmap;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Platform/X11/ScopedXCB.inl>
|
||||
|
||||
#endif // NAZARA_SCOPEDXCB_HPP
|
||||
47
src/Nazara/Platform/X11/ScopedXCB.inl
Normal file
47
src/Nazara/Platform/X11/ScopedXCB.inl
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
template <typename T>
|
||||
ScopedXCB<T>::ScopedXCB(T* pointer) :
|
||||
m_pointer(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ScopedXCB<T>::~ScopedXCB()
|
||||
{
|
||||
std::free(m_pointer);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* ScopedXCB<T>::operator ->() const
|
||||
{
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T** ScopedXCB<T>::operator &()
|
||||
{
|
||||
return &m_pointer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ScopedXCB<T>::operator bool() const
|
||||
{
|
||||
return m_pointer != nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* ScopedXCB<T>::get() const
|
||||
{
|
||||
return m_pointer;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Platform/DebugOff.hpp>
|
||||
169
src/Nazara/Platform/X11/VideoModeImpl.cpp
Normal file
169
src/Nazara/Platform/X11/VideoModeImpl.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Platform/X11/VideoModeImpl.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Platform/VideoMode.hpp>
|
||||
#include <Nazara/Platform/X11/Display.hpp>
|
||||
#include <xcb/randr.h>
|
||||
#include <algorithm>
|
||||
#include <Nazara/Platform/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
VideoMode VideoModeImpl::GetDesktopMode()
|
||||
{
|
||||
VideoMode desktopMode;
|
||||
|
||||
ScopedXCBConnection connection;
|
||||
|
||||
// Retrieve the default screen
|
||||
xcb_screen_t* screen = X11::XCBDefaultScreen(connection);
|
||||
|
||||
ScopedXCB<xcb_generic_error_t> 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 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<xcb_randr_query_version_reply_t> 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<xcb_randr_get_screen_info_reply_t> 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<VideoMode>& modes)
|
||||
{
|
||||
ScopedXCBConnection connection;
|
||||
|
||||
// Retrieve the default screen
|
||||
xcb_screen_t* screen = X11::XCBDefaultScreen(connection);
|
||||
|
||||
ScopedXCB<xcb_generic_error_t> 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<xcb_randr_query_version_reply_t> 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<xcb_randr_get_screen_info_reply_t> 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))
|
||||
{
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/Nazara/Platform/X11/VideoModeImpl.hpp
Normal file
23
src/Nazara/Platform/X11/VideoModeImpl.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_VIDEOMODEIMPL_HPP
|
||||
#define NAZARA_VIDEOMODEIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Platform/VideoMode.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class VideoModeImpl
|
||||
{
|
||||
public:
|
||||
static VideoMode GetDesktopMode();
|
||||
static void GetFullscreenModes(std::vector<VideoMode>& modes);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NNAZARA_VIDEOMODEIMPL_HPP
|
||||
1569
src/Nazara/Platform/X11/WindowImpl.cpp
Normal file
1569
src/Nazara/Platform/X11/WindowImpl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
125
src/Nazara/Platform/X11/WindowImpl.hpp
Normal file
125
src/Nazara/Platform/X11/WindowImpl.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Platform module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// Interface inspirée de la SFML par Laurent Gomila
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_WINDOWIMPL_HPP
|
||||
#define NAZARA_WINDOWIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/Thread.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Platform/Enums.hpp>
|
||||
#include <Nazara/Platform/Keyboard.hpp>
|
||||
#include <Nazara/Platform/X11/Display.hpp>
|
||||
#include <xcb/randr.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class ConditionVariable;
|
||||
class Mutex;
|
||||
class Cursor;
|
||||
class Icon;
|
||||
class VideoMode;
|
||||
class Window;
|
||||
|
||||
class WindowImpl
|
||||
{
|
||||
public:
|
||||
WindowImpl(Window* parent);
|
||||
WindowImpl(const WindowImpl&) = delete;
|
||||
WindowImpl(WindowImpl&&) = delete; ///TODO?
|
||||
~WindowImpl();
|
||||
|
||||
bool Create(const VideoMode& mode, const String& title, WindowStyleFlags style);
|
||||
bool Create(WindowHandle handle);
|
||||
|
||||
void Destroy();
|
||||
|
||||
void EnableKeyRepeat(bool enable);
|
||||
void EnableSmoothScrolling(bool enable);
|
||||
|
||||
WindowHandle GetHandle() const;
|
||||
unsigned int GetHeight() const;
|
||||
Vector2i GetPosition() const;
|
||||
Vector2ui GetSize() const;
|
||||
WindowStyleFlags GetStyle() const;
|
||||
String GetTitle() const;
|
||||
unsigned int GetWidth() const;
|
||||
|
||||
bool HasFocus() const;
|
||||
|
||||
void IgnoreNextMouseEvent(int mouseX, int mouseY);
|
||||
|
||||
bool IsMinimized() const;
|
||||
bool IsVisible() const;
|
||||
|
||||
void ProcessEvents(bool block);
|
||||
|
||||
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);
|
||||
|
||||
WindowImpl& operator=(const WindowImpl&) = delete;
|
||||
WindowImpl& operator=(WindowImpl&&) = delete; ///TODO?
|
||||
|
||||
static bool Initialize();
|
||||
static void Uninitialize();
|
||||
|
||||
private:
|
||||
|
||||
void CleanUp();
|
||||
xcb_keysym_t ConvertKeyCodeToKeySym(xcb_keycode_t keycode, uint16_t state);
|
||||
Keyboard::Key ConvertVirtualKey(xcb_keysym_t symbol);
|
||||
void CommonInitialize();
|
||||
|
||||
char32_t GetRepresentation(xcb_keysym_t keysym) const;
|
||||
|
||||
void ProcessEvent(xcb_generic_event_t* windowEvent);
|
||||
|
||||
void ResetVideoMode();
|
||||
|
||||
void SetMotifHints();
|
||||
void SetVideoMode(const VideoMode& mode);
|
||||
void SwitchToFullscreen();
|
||||
|
||||
bool UpdateNormalHints();
|
||||
void UpdateEventQueue(xcb_generic_event_t* event);
|
||||
|
||||
static void WindowThread(WindowImpl* window, Mutex* mutex, ConditionVariable* condition);
|
||||
|
||||
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;
|
||||
Thread m_thread;
|
||||
WindowStyleFlags m_style;
|
||||
Window* m_parent;
|
||||
bool m_eventListener;
|
||||
bool m_ownsWindow;
|
||||
bool m_smoothScrolling;
|
||||
bool m_threadActive;
|
||||
Vector2i m_mousePos;
|
||||
bool m_keyRepeat;
|
||||
|
||||
struct
|
||||
{
|
||||
xcb_generic_event_t* curr = nullptr;
|
||||
xcb_generic_event_t* next = nullptr;
|
||||
} m_eventQueue;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_WINDOWIMPL_HPP
|
||||
Reference in New Issue
Block a user