Consolidate all xcb functionality into one subdirectory

The Linux platform has multiple windowing systems. Support for xcb is
currently in progress, support for Wayland is planned in the future. The
way the current xcb support is included is by making some file with a
`_xcb` suffix, and placing `#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB` around
most of that file's contents.

With this change, all of the code in AzFramework that uses xcb directly is
inside the `Platform/Common/Xcb` subdirectory. It greatly reduces the
amount of code in compile-time `#ifdef` checks for the chosen windowing
system. It also provides a logical place to include O3DE-specific xcb
C++ wrappers and interfaces, without polluting non-xcb related code.

Signed-off-by: Chris Burel <burelc@amazon.com>
monroegm-disable-blank-issue-2
Chris Burel 4 years ago
parent 08e3d14013
commit f5effaabcc

@ -9,7 +9,7 @@
#include "QtEditorApplication.h" #include "QtEditorApplication.h"
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <AzFramework/API/ApplicationAPI_Linux.h> #include <AzFramework/XcbEventHandler.h>
#endif #endif
namespace Editor namespace Editor
@ -19,7 +19,7 @@ namespace Editor
if (GetIEditor()->IsInGameMode()) if (GetIEditor()->IsInGameMode())
{ {
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
AzFramework::LinuxXcbEventHandlerBus::Broadcast(&AzFramework::LinuxXcbEventHandler::HandleXcbEvent, static_cast<xcb_generic_event_t*>(message)); AzFramework::XcbEventHandlerBus::Broadcast(&AzFramework::XcbEventHandler::HandleXcbEvent, static_cast<xcb_generic_event_t*>(message));
#endif #endif
return true; return true;
} }

@ -6,29 +6,26 @@
* *
*/ */
#include <AzFramework/API/ApplicationAPI_Platform.h> #include <AzFramework/XcbApplication.h>
#include <AzFramework/Application/Application.h> #include <AzFramework/XcbEventHandler.h>
#include "Application_Linux_xcb.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework namespace AzFramework
{ {
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
class LinuxXcbConnectionManagerImpl class XcbConnectionManagerImpl
: public LinuxXcbConnectionManagerBus::Handler : public XcbConnectionManagerBus::Handler
{ {
public: public:
LinuxXcbConnectionManagerImpl() XcbConnectionManagerImpl()
{ {
m_xcbConnection = xcb_connect(nullptr, nullptr); m_xcbConnection = xcb_connect(nullptr, nullptr);
AZ_Error("ApplicationLinux", m_xcbConnection != nullptr, "Unable to connect to X11 Server."); AZ_Error("Application", m_xcbConnection != nullptr, "Unable to connect to X11 Server.");
LinuxXcbConnectionManagerBus::Handler::BusConnect(); XcbConnectionManagerBus::Handler::BusConnect();
} }
~LinuxXcbConnectionManagerImpl() ~XcbConnectionManagerImpl() override
{ {
LinuxXcbConnectionManagerBus::Handler::BusDisconnect(); XcbConnectionManagerBus::Handler::BusDisconnect();
xcb_disconnect(m_xcbConnection); xcb_disconnect(m_xcbConnection);
} }
@ -42,53 +39,51 @@ namespace AzFramework
}; };
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
ApplicationLinux_xcb::ApplicationLinux_xcb() XcbApplication::XcbApplication()
{ {
LinuxLifecycleEvents::Bus::Handler::BusConnect(); LinuxLifecycleEvents::Bus::Handler::BusConnect();
m_xcbConnectionManager = AZStd::make_unique<LinuxXcbConnectionManagerImpl>(); m_xcbConnectionManager = AZStd::make_unique<XcbConnectionManagerImpl>();
if (LinuxXcbConnectionManagerInterface::Get() == nullptr) if (XcbConnectionManagerInterface::Get() == nullptr)
{ {
LinuxXcbConnectionManagerInterface::Register(m_xcbConnectionManager.get()); XcbConnectionManagerInterface::Register(m_xcbConnectionManager.get());
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
ApplicationLinux_xcb::~ApplicationLinux_xcb() XcbApplication::~XcbApplication()
{ {
if (LinuxXcbConnectionManagerInterface::Get() == m_xcbConnectionManager.get()) if (XcbConnectionManagerInterface::Get() == m_xcbConnectionManager.get())
{ {
LinuxXcbConnectionManagerInterface::Unregister(m_xcbConnectionManager.get()); XcbConnectionManagerInterface::Unregister(m_xcbConnectionManager.get());
} }
m_xcbConnectionManager.reset(); m_xcbConnectionManager.reset();
LinuxLifecycleEvents::Bus::Handler::BusDisconnect(); LinuxLifecycleEvents::Bus::Handler::BusDisconnect();
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void ApplicationLinux_xcb::PumpSystemEventLoopOnce() void XcbApplication::PumpSystemEventLoopOnce()
{ {
if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection()) if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection())
{ {
if (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection)) if (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection))
{ {
LinuxXcbEventHandlerBus::Broadcast(&LinuxXcbEventHandlerBus::Events::HandleXcbEvent, event); XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event);
free(event); free(event);
} }
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void ApplicationLinux_xcb::PumpSystemEventLoopUntilEmpty() void XcbApplication::PumpSystemEventLoopUntilEmpty()
{ {
if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection()) if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection())
{ {
while (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection)) while (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection))
{ {
LinuxXcbEventHandlerBus::Broadcast(&LinuxXcbEventHandlerBus::Events::HandleXcbEvent, event); XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event);
free(event); free(event);
} }
} }
} }
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework } // namespace AzFramework

@ -5,27 +5,24 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT * SPDX-License-Identifier: Apache-2.0 OR MIT
* *
*/ */
#pragma once #pragma once
#include <AzFramework/API/ApplicationAPI_Platform.h> #include <AzFramework/API/ApplicationAPI_Platform.h>
#include <AzFramework/Application/Application.h> #include <AzFramework/Application/Application.h>
#include <AzFramework/XcbConnectionManager.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework namespace AzFramework
{ {
class XcbApplication
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
////////////////////////////////////////////////////////////////////////////////////////////////
class ApplicationLinux_xcb
: public Application::Implementation : public Application::Implementation
, public LinuxLifecycleEvents::Bus::Handler , public LinuxLifecycleEvents::Bus::Handler
{ {
public: public:
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
AZ_CLASS_ALLOCATOR(ApplicationLinux_xcb, AZ::SystemAllocator, 0); AZ_CLASS_ALLOCATOR(XcbApplication, AZ::SystemAllocator, 0);
ApplicationLinux_xcb(); XcbApplication();
~ApplicationLinux_xcb() override; ~XcbApplication() override;
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// Application::Implementation // Application::Implementation
@ -33,9 +30,6 @@ namespace AzFramework
void PumpSystemEventLoopUntilEmpty() override; void PumpSystemEventLoopUntilEmpty() override;
private: private:
AZStd::unique_ptr<LinuxXcbConnectionManager> m_xcbConnectionManager; AZStd::unique_ptr<XcbConnectionManager> m_xcbConnectionManager;
}; };
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework } // namespace AzFramework

@ -0,0 +1,42 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/RTTI/RTTI.h>
#include <xcb/xcb.h>
namespace AzFramework
{
class XcbConnectionManager
{
public:
AZ_RTTI(XcbConnectionManager, "{1F756E14-8D74-42FD-843C-4863307710DB}");
virtual ~XcbConnectionManager() = default;
virtual xcb_connection_t* GetXcbConnection() const = 0;
};
class XcbConnectionManagerBusTraits
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
};
using XcbConnectionManagerBus = AZ::EBus<XcbConnectionManager, XcbConnectionManagerBusTraits>;
using XcbConnectionManagerInterface = AZ::Interface<XcbConnectionManager>;
} // namespace AzFramework

@ -0,0 +1,40 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
#include <AzCore/RTTI/RTTI.h>
#include <xcb/xcb.h>
namespace AzFramework
{
class XcbEventHandler
{
public:
AZ_RTTI(XcbEventHandler, "{3F756E14-8D74-42FD-843C-4863307710DB}");
virtual ~XcbEventHandler() = default;
virtual void HandleXcbEvent(xcb_generic_event_t* event) = 0;
};
class XcbEventHandlerBusTraits
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
};
using XcbEventHandlerBus = AZ::EBus<XcbEventHandler, XcbEventHandlerBusTraits>;
} // namespace AzFramework

@ -6,9 +6,10 @@
* *
*/ */
#include <AzCore/std/typetraits/integral_constant.h>
#include <AzFramework/API/ApplicationAPI_Linux.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h> #include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/XcbEventHandler.h>
#include <AzFramework/XcbConnectionManager.h>
#include <AzFramework/XcbInputDeviceKeyboard.h>
#define explicit ExplicitIsACXXKeyword #define explicit ExplicitIsACXXKeyword
#include <xcb/xkb.h> #include <xcb/xkb.h>
@ -19,34 +20,26 @@
namespace AzFramework namespace AzFramework
{ {
class InputDeviceKeyboardXcb XcbInputDeviceKeyboard::XcbInputDeviceKeyboard(InputDeviceKeyboard& inputDevice)
: public InputDeviceKeyboard::Implementation
, public LinuxXcbEventHandlerBus::Handler
{
public:
AZ_CLASS_ALLOCATOR(InputDeviceKeyboardXcb, AZ::SystemAllocator, 0);
using InputDeviceKeyboard::Implementation::Implementation;
InputDeviceKeyboardXcb(InputDeviceKeyboard& inputDevice)
: InputDeviceKeyboard::Implementation(inputDevice) : InputDeviceKeyboard::Implementation(inputDevice)
{ {
LinuxXcbEventHandlerBus::Handler::BusConnect(); XcbEventHandlerBus::Handler::BusConnect();
auto* interface = AzFramework::LinuxXcbConnectionManagerInterface::Get(); auto* interface = AzFramework::XcbConnectionManagerInterface::Get();
if (!interface) if (!interface)
{ {
AZ_Warning("ApplicationLinux", false, "XCB interface not available"); AZ_Warning("ApplicationLinux", false, "XCB interface not available");
return; return;
} }
auto* connection = AzFramework::LinuxXcbConnectionManagerInterface::Get()->GetXcbConnection(); auto* connection = interface->GetXcbConnection();
if (!connection) if (!connection)
{ {
AZ_Warning("ApplicationLinux", false, "XCB connection not available"); AZ_Warning("ApplicationLinux", false, "XCB connection not available");
return; return;
} }
AZStd::unique_ptr<xcb_xkb_use_extension_reply_t, DeleterForFreeFn<::std::free>> xkbUseExtensionReply{ XcbStdFreePtr<xcb_xkb_use_extension_reply_t> xkbUseExtensionReply{
xcb_xkb_use_extension_reply(connection, xcb_xkb_use_extension(connection, 1, 0), nullptr) xcb_xkb_use_extension_reply(connection, xcb_xkb_use_extension(connection, 1, 0), nullptr)
}; };
if (!xkbUseExtensionReply) if (!xkbUseExtensionReply)
@ -69,32 +62,33 @@ namespace AzFramework
m_initialized = true; m_initialized = true;
} }
bool IsConnected() const override bool XcbInputDeviceKeyboard::IsConnected() const
{ {
return m_initialized; auto* connection = AzFramework::XcbConnectionManagerInterface::Get()->GetXcbConnection();
return connection && !xcb_connection_has_error(connection);
} }
bool HasTextEntryStarted() const override bool XcbInputDeviceKeyboard::HasTextEntryStarted() const
{ {
return false; return false;
} }
void TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options) override void XcbInputDeviceKeyboard::TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options)
{ {
} }
void TextEntryStop() override void XcbInputDeviceKeyboard::TextEntryStop()
{ {
} }
void TickInputDevice() override void XcbInputDeviceKeyboard::TickInputDevice()
{ {
ProcessRawEventQueues(); ProcessRawEventQueues();
} }
void HandleXcbEvent(xcb_generic_event_t* event) override void XcbInputDeviceKeyboard::HandleXcbEvent(xcb_generic_event_t* event)
{ {
if (!IsConnected()) if (!m_initialized)
{ {
return; return;
} }
@ -126,8 +120,7 @@ namespace AzFramework
} }
} }
private: [[nodiscard]] const InputChannelId* XcbInputDeviceKeyboard::InputChannelFromKeyEvent(xcb_keycode_t code) const
[[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const
{ {
const xcb_keysym_t keysym = xkb_state_key_get_one_sym(m_xkbState.get(), code); const xcb_keysym_t keysym = xkb_state_key_get_one_sym(m_xkbState.get(), code);
@ -275,19 +268,4 @@ namespace AzFramework
default: return nullptr; default: return nullptr;
} }
} }
template<auto freeFn>
using DeleterForFreeFn = AZStd::integral_constant<decltype(freeFn), freeFn>;
AZStd::unique_ptr<xkb_context, DeleterForFreeFn<xkb_context_unref>> m_xkbContext;
AZStd::unique_ptr<xkb_keymap, DeleterForFreeFn<xkb_keymap_unref>> m_xkbKeymap;
AZStd::unique_ptr<xkb_state, DeleterForFreeFn<xkb_state_unref>> m_xkbState;
int m_coreDeviceId{-1};
bool m_initialized{false};
};
InputDeviceKeyboard::Implementation* InputDeviceKeyboard::Implementation::Create(InputDeviceKeyboard& inputDevice)
{
return aznew InputDeviceKeyboardXcb(inputDevice);
}
} // namespace AzFramework } // namespace AzFramework

@ -0,0 +1,46 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/XcbEventHandler.h>
#include <AzFramework/XcbInterface.h>
#include <xcb/xcb.h>
#include <xkbcommon/xkbcommon.h>
namespace AzFramework
{
class XcbInputDeviceKeyboard
: public InputDeviceKeyboard::Implementation
, public XcbEventHandlerBus::Handler
{
public:
AZ_CLASS_ALLOCATOR(XcbInputDeviceKeyboard, AZ::SystemAllocator, 0);
using InputDeviceKeyboard::Implementation::Implementation;
XcbInputDeviceKeyboard(InputDeviceKeyboard& inputDevice);
bool IsConnected() const override;
bool HasTextEntryStarted() const override;
void TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options) override;
void TextEntryStop() override;
void TickInputDevice() override;
void HandleXcbEvent(xcb_generic_event_t* event) override;
private:
[[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const;
XcbUniquePtr<xkb_context, xkb_context_unref> m_xkbContext;
XcbUniquePtr<xkb_keymap, xkb_keymap_unref> m_xkbKeymap;
XcbUniquePtr<xkb_state, xkb_state_unref> m_xkbState;
int m_coreDeviceId{-1};
bool m_initialized{false};
};
} // namespace AzFramework

@ -0,0 +1,38 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <xcb/xcb.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
namespace AzFramework
{
// @brief Wrap a function pointer in a type
// This serves as a convenient way to wrap a function pointer in a given
// type. That type can then be used in a `unique_ptr` or `shared_ptr`.
// Using a type instead of a function pointer by value prevents the need to
// copy the pointer when copying the smart poiner.
template<auto Callable>
struct XcbDeleterFreeFunctionWrapper
{
using value_type = decltype(Callable);
static constexpr value_type s_value = Callable;
constexpr operator value_type() const noexcept
{
return s_value;
}
};
template<typename T, auto fn>
using XcbUniquePtr = AZStd::unique_ptr<T, XcbDeleterFreeFunctionWrapper<fn>>;
template<typename T>
using XcbStdFreePtr = XcbUniquePtr<T, ::free>;
} // namespace AzFramework

@ -6,41 +6,37 @@
* *
*/ */
#include <AzFramework/API/ApplicationAPI_Platform.h>
#include <AzFramework/Application/Application.h> #include <AzFramework/Application/Application.h>
#include <AzFramework/Windowing/NativeWindow.h> #include <AzFramework/Windowing/NativeWindow.h>
#include <xcb/xcb.h> #include <AzFramework/XcbNativeWindow.h>
#include <AzFramework/XcbConnectionManager.h>
#include "NativeWindow_Linux_xcb.h" #include <xcb/xcb.h>
namespace AzFramework namespace AzFramework
{ {
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB [[maybe_unused]] const char XcbErrorWindow[] = "XcbNativeWindow";
[[maybe_unused]] const char LinuxXcbErrorWindow[] = "NativeWindow_Linux_xcb";
static constexpr uint8_t s_XcbFormatDataSize = 32; // Format indicator for xcb for client messages static constexpr uint8_t s_XcbFormatDataSize = 32; // Format indicator for xcb for client messages
static constexpr uint16_t s_DefaultXcbWindowBorderWidth = 4; // The default border with in pixels if a border was specified static constexpr uint16_t s_DefaultXcbWindowBorderWidth = 4; // The default border with in pixels if a border was specified
static constexpr uint8_t s_XcbResponseTypeMask = 0x7f; // Mask to extract the specific event type from an xcb event static constexpr uint8_t s_XcbResponseTypeMask = 0x7f; // Mask to extract the specific event type from an xcb event
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
NativeWindowImpl_Linux_xcb::NativeWindowImpl_Linux_xcb() XcbNativeWindow::XcbNativeWindow()
: NativeWindow::Implementation() : NativeWindow::Implementation()
{ {
if (auto xcbConnectionManager = AzFramework::LinuxXcbConnectionManagerInterface::Get(); if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get();
xcbConnectionManager != nullptr) xcbConnectionManager != nullptr)
{ {
m_xcbConnection = xcbConnectionManager->GetXcbConnection(); m_xcbConnection = xcbConnectionManager->GetXcbConnection();
} }
AZ_Error(LinuxXcbErrorWindow, m_xcbConnection != nullptr, "Unable to get XCB Connection"); AZ_Error(XcbErrorWindow, m_xcbConnection != nullptr, "Unable to get XCB Connection");
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
NativeWindowImpl_Linux_xcb::~NativeWindowImpl_Linux_xcb() XcbNativeWindow::~XcbNativeWindow() = default;
{
}
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void NativeWindowImpl_Linux_xcb::InitWindow(const AZStd::string& title, void XcbNativeWindow::InitWindow(const AZStd::string& title,
const WindowGeometry& geometry, const WindowGeometry& geometry,
const WindowStyleMasks& styleMasks) const WindowStyleMasks& styleMasks)
{ {
@ -98,13 +94,13 @@ namespace AzFramework
xcb_intern_atom_cookie_t cookieProtocol = xcb_intern_atom(m_xcbConnection, 1, strlen(wmProtocolString), wmProtocolString); xcb_intern_atom_cookie_t cookieProtocol = xcb_intern_atom(m_xcbConnection, 1, strlen(wmProtocolString), wmProtocolString);
xcb_intern_atom_reply_t* replyProtocol = xcb_intern_atom_reply(m_xcbConnection, cookieProtocol, nullptr); xcb_intern_atom_reply_t* replyProtocol = xcb_intern_atom_reply(m_xcbConnection, cookieProtocol, nullptr);
AZ_Error(LinuxXcbErrorWindow, replyProtocol != nullptr, "Unable to query xcb '%s' atom", wmProtocolString); AZ_Error(XcbErrorWindow, replyProtocol != nullptr, "Unable to query xcb '%s' atom", wmProtocolString);
m_xcbAtomProtocols = replyProtocol->atom; m_xcbAtomProtocols = replyProtocol->atom;
const static char* wmDeleteWindowString = "WM_DELETE_WINDOW"; const static char* wmDeleteWindowString = "WM_DELETE_WINDOW";
xcb_intern_atom_cookie_t cookieDeleteWindow = xcb_intern_atom(m_xcbConnection, 0, strlen(wmDeleteWindowString), wmDeleteWindowString); xcb_intern_atom_cookie_t cookieDeleteWindow = xcb_intern_atom(m_xcbConnection, 0, strlen(wmDeleteWindowString), wmDeleteWindowString);
xcb_intern_atom_reply_t* replyDeleteWindow = xcb_intern_atom_reply(m_xcbConnection, cookieDeleteWindow, nullptr); xcb_intern_atom_reply_t* replyDeleteWindow = xcb_intern_atom_reply(m_xcbConnection, cookieDeleteWindow, nullptr);
AZ_Error(LinuxXcbErrorWindow, replyDeleteWindow != nullptr, "Unable to query xcb '%s' atom", wmDeleteWindowString); AZ_Error(XcbErrorWindow, replyDeleteWindow != nullptr, "Unable to query xcb '%s' atom", wmDeleteWindowString);
m_xcbAtomDeleteWindow = replyDeleteWindow->atom; m_xcbAtomDeleteWindow = replyDeleteWindow->atom;
xcbCheckResult = xcb_change_property_checked(m_xcbConnection, xcbCheckResult = xcb_change_property_checked(m_xcbConnection,
@ -123,9 +119,9 @@ namespace AzFramework
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void NativeWindowImpl_Linux_xcb::Activate() void XcbNativeWindow::Activate()
{ {
LinuxXcbEventHandlerBus::Handler::BusConnect(); XcbEventHandlerBus::Handler::BusConnect();
if (!m_activated) // nothing to do if window was already activated if (!m_activated) // nothing to do if window was already activated
{ {
@ -137,7 +133,7 @@ namespace AzFramework
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void NativeWindowImpl_Linux_xcb::Deactivate() void XcbNativeWindow::Deactivate()
{ {
if (m_activated) // nothing to do if window was already deactivated if (m_activated) // nothing to do if window was already deactivated
{ {
@ -148,17 +144,17 @@ namespace AzFramework
xcb_unmap_window(m_xcbConnection, m_xcbWindow); xcb_unmap_window(m_xcbConnection, m_xcbWindow);
xcb_flush(m_xcbConnection); xcb_flush(m_xcbConnection);
} }
LinuxXcbEventHandlerBus::Handler::BusDisconnect(); XcbEventHandlerBus::Handler::BusDisconnect();
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
NativeWindowHandle NativeWindowImpl_Linux_xcb::GetWindowHandle() const NativeWindowHandle XcbNativeWindow::GetWindowHandle() const
{ {
return reinterpret_cast<NativeWindowHandle>(m_xcbWindow); return reinterpret_cast<NativeWindowHandle>(m_xcbWindow);
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void NativeWindowImpl_Linux_xcb::SetWindowTitle(const AZStd::string& title) void XcbNativeWindow::SetWindowTitle(const AZStd::string& title)
{ {
xcb_void_cookie_t xcbCheckResult; xcb_void_cookie_t xcbCheckResult;
xcbCheckResult = xcb_change_property(m_xcbConnection, xcbCheckResult = xcb_change_property(m_xcbConnection,
@ -173,7 +169,7 @@ namespace AzFramework
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void NativeWindowImpl_Linux_xcb::ResizeClientArea(WindowSize clientAreaSize) void XcbNativeWindow::ResizeClientArea(WindowSize clientAreaSize)
{ {
const uint32_t values[] = { clientAreaSize.m_width, clientAreaSize.m_height }; const uint32_t values[] = { clientAreaSize.m_width, clientAreaSize.m_height };
@ -184,7 +180,7 @@ namespace AzFramework
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
uint32_t NativeWindowImpl_Linux_xcb::GetDisplayRefreshRate() const uint32_t XcbNativeWindow::GetDisplayRefreshRate() const
{ {
// [GFX TODO][GHI - 2678] // [GFX TODO][GHI - 2678]
// Using 60 for now until proper support is added // Using 60 for now until proper support is added
@ -192,7 +188,7 @@ namespace AzFramework
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
bool NativeWindowImpl_Linux_xcb::ValidateXcbResult(xcb_void_cookie_t cookie) bool XcbNativeWindow::ValidateXcbResult(xcb_void_cookie_t cookie)
{ {
bool result = true; bool result = true;
if (xcb_generic_error_t* error = xcb_request_check(m_xcbConnection, cookie)) if (xcb_generic_error_t* error = xcb_request_check(m_xcbConnection, cookie))
@ -204,7 +200,7 @@ namespace AzFramework
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void NativeWindowImpl_Linux_xcb::HandleXcbEvent(xcb_generic_event_t* event) void XcbNativeWindow::HandleXcbEvent(xcb_generic_event_t* event)
{ {
switch (event->response_type & s_XcbResponseTypeMask) switch (event->response_type & s_XcbResponseTypeMask)
{ {
@ -233,7 +229,7 @@ namespace AzFramework
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void NativeWindowImpl_Linux_xcb::WindowSizeChanged(const uint32_t width, const uint32_t height) void XcbNativeWindow::WindowSizeChanged(const uint32_t width, const uint32_t height)
{ {
if (m_width != width || m_height != height) if (m_width != width || m_height != height)
{ {
@ -246,7 +242,4 @@ namespace AzFramework
} }
} }
} }
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework } // namespace AzFramework

@ -5,24 +5,25 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT * SPDX-License-Identifier: Apache-2.0 OR MIT
* *
*/ */
#pragma once #pragma once
#include <AzFramework/API/ApplicationAPI_Platform.h>
#include <AzFramework/Application/Application.h> #include <AzFramework/Application/Application.h>
#include <AzFramework/Windowing/NativeWindow.h> #include <AzFramework/Windowing/NativeWindow.h>
#include <AzFramework/XcbEventHandler.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
namespace AzFramework namespace AzFramework
{ {
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB class XcbNativeWindow final
class NativeWindowImpl_Linux_xcb final
: public NativeWindow::Implementation : public NativeWindow::Implementation
, public LinuxXcbEventHandlerBus::Handler , public XcbEventHandlerBus::Handler
{ {
public: public:
AZ_CLASS_ALLOCATOR(NativeWindowImpl_Linux_xcb, AZ::SystemAllocator, 0); AZ_CLASS_ALLOCATOR(XcbNativeWindow, AZ::SystemAllocator, 0);
NativeWindowImpl_Linux_xcb(); XcbNativeWindow();
~NativeWindowImpl_Linux_xcb() override; ~XcbNativeWindow() override;
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// NativeWindow::Implementation // NativeWindow::Implementation
@ -37,7 +38,7 @@ namespace AzFramework
uint32_t GetDisplayRefreshRate() const override; uint32_t GetDisplayRefreshRate() const override;
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// LinuxXcbEventHandlerBus::Handler // XcbEventHandlerBus::Handler
void HandleXcbEvent(xcb_generic_event_t* event) override; void HandleXcbEvent(xcb_generic_event_t* event) override;
private: private:
@ -49,6 +50,4 @@ namespace AzFramework
xcb_atom_t m_xcbAtomProtocols; xcb_atom_t m_xcbAtomProtocols;
xcb_atom_t m_xcbAtomDeleteWindow; xcb_atom_t m_xcbAtomDeleteWindow;
}; };
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework } // namespace AzFramework

@ -0,0 +1,18 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
set(FILES
AzFramework/XcbApplication.cpp
AzFramework/XcbApplication.h
AzFramework/XcbConnectionManager.h
AzFramework/XcbInputDeviceKeyboard.cpp
AzFramework/XcbInputDeviceKeyboard.h
AzFramework/XcbInterface.h
AzFramework/XcbNativeWindow.cpp
AzFramework/XcbNativeWindow.h
)

@ -12,10 +12,6 @@
#include <AzCore/Interface/Interface.h> #include <AzCore/Interface/Interface.h>
#include <AzCore/EBus/EBus.h> #include <AzCore/EBus/EBus.h>
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <xcb/xcb.h>
#endif // LY_COMPILE_DEFINITIONS
namespace AzFramework namespace AzFramework
{ {
class LinuxLifecycleEvents class LinuxLifecycleEvents
@ -30,54 +26,4 @@ namespace AzFramework
using Bus = AZ::EBus<LinuxLifecycleEvents>; using Bus = AZ::EBus<LinuxLifecycleEvents>;
}; };
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
class LinuxXcbConnectionManager
{
public:
AZ_RTTI(LinuxXcbConnectionManager, "{1F756E14-8D74-42FD-843C-4863307710DB}");
virtual ~LinuxXcbConnectionManager() = default;
virtual xcb_connection_t* GetXcbConnection() const = 0;
};
class LinuxXcbConnectionManagerBusTraits
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
};
using LinuxXcbConnectionManagerBus = AZ::EBus<LinuxXcbConnectionManager, LinuxXcbConnectionManagerBusTraits>;
using LinuxXcbConnectionManagerInterface = AZ::Interface<LinuxXcbConnectionManager>;
class LinuxXcbEventHandler
{
public:
AZ_RTTI(LinuxXcbEventHandler, "{3F756E14-8D74-42FD-843C-4863307710DB}");
virtual ~LinuxXcbEventHandler() = default;
virtual void HandleXcbEvent(xcb_generic_event_t* event) = 0;
};
class LinuxXcbEventHandlerBusTraits
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
};
using LinuxXcbEventHandlerBus = AZ::EBus<LinuxXcbEventHandler, LinuxXcbEventHandlerBusTraits>;
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework } // namespace AzFramework

@ -8,7 +8,9 @@
#include <AzFramework/Application/Application.h> #include <AzFramework/Application/Application.h>
#include "Application_Linux_xcb.h" #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <AzFramework/XcbApplication.h>
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework namespace AzFramework
@ -17,7 +19,7 @@ namespace AzFramework
Application::Implementation* Application::Implementation::Create() Application::Implementation* Application::Implementation::Create()
{ {
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
return aznew ApplicationLinux_xcb(); return aznew XcbApplication();
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND #elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
#error "Linux Window Manager Wayland not supported." #error "Linux Window Manager Wayland not supported."
return nullptr; return nullptr;

@ -0,0 +1,27 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <AzFramework/XcbInputDeviceKeyboard.h>
#endif
namespace AzFramework
{
InputDeviceKeyboard::Implementation* InputDeviceKeyboard::Implementation::Create(InputDeviceKeyboard& inputDevice)
{
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
return aznew XcbInputDeviceKeyboard(inputDevice);
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
#error "Linux Window Manager Wayland not supported."
return nullptr;
#else
#error "Linux Window Manager not recognized."
return nullptr;
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
}
} // namespace AzFramework

@ -6,14 +6,16 @@
* *
*/ */
#include "NativeWindow_Linux_xcb.h" #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <AzFramework/XcbNativeWindow.h>
#endif
namespace AzFramework namespace AzFramework
{ {
NativeWindow::Implementation* NativeWindow::Implementation::Create() NativeWindow::Implementation* NativeWindow::Implementation::Create()
{ {
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
return aznew NativeWindowImpl_Linux_xcb(); return aznew XcbNativeWindow();
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND #elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
#error "Linux Window Manager Wayland not supported." #error "Linux Window Manager Wayland not supported."
return nullptr; return nullptr;
@ -22,5 +24,4 @@ namespace AzFramework
return nullptr; return nullptr;
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} }
} // namespace AzFramework } // namespace AzFramework

@ -10,6 +10,14 @@
# Only 'xcb' and 'wayland' are recognized # Only 'xcb' and 'wayland' are recognized
if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb") if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
set(LY_INCLUDE_DIRECTORIES
PUBLIC
Platform/Common/Xcb
)
set(LY_FILES_CMAKE
Platform/Common/Xcb/azframework_xcb_files.cmake
)
set(LY_BUILD_DEPENDENCIES set(LY_BUILD_DEPENDENCIES
PRIVATE PRIVATE
3rdParty::X11::xcb 3rdParty::X11::xcb
@ -18,8 +26,6 @@ if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
3rdParty::X11::xkbcommon_X11 3rdParty::X11::xkbcommon_X11
) )
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland") elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland")
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND) set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND)

@ -12,8 +12,6 @@ set(FILES
AzFramework/API/ApplicationAPI_Platform.h AzFramework/API/ApplicationAPI_Platform.h
AzFramework/API/ApplicationAPI_Linux.h AzFramework/API/ApplicationAPI_Linux.h
AzFramework/Application/Application_Linux.cpp AzFramework/Application/Application_Linux.cpp
AzFramework/Application/Application_Linux_xcb.h
AzFramework/Application/Application_Linux_xcb.cpp
AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp
AzFramework/Process/ProcessWatcher_Linux.cpp AzFramework/Process/ProcessWatcher_Linux.cpp
AzFramework/Process/ProcessCommon.h AzFramework/Process/ProcessCommon.h
@ -22,10 +20,8 @@ set(FILES
../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp ../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp
../Common/Default/AzFramework/TargetManagement/TargetManagementComponent_Default.cpp ../Common/Default/AzFramework/TargetManagement/TargetManagementComponent_Default.cpp
AzFramework/Windowing/NativeWindow_Linux.cpp AzFramework/Windowing/NativeWindow_Linux.cpp
AzFramework/Windowing/NativeWindow_Linux_xcb.h
AzFramework/Windowing/NativeWindow_Linux_xcb.cpp
../Common/Unimplemented/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad_Unimplemented.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad_Unimplemented.cpp
AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.cpp AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp
../Common/Unimplemented/AzFramework/Input/Devices/Motion/InputDeviceMotion_Unimplemented.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Motion/InputDeviceMotion_Unimplemented.cpp
../Common/Unimplemented/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Unimplemented.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Unimplemented.cpp
../Common/Unimplemented/AzFramework/Input/Devices/Touch/InputDeviceTouch_Unimplemented.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Touch/InputDeviceTouch_Unimplemented.cpp

@ -10,6 +10,10 @@
#include <RHI/Instance.h> #include <RHI/Instance.h>
#include <RHI/WSISurface.h> #include <RHI/WSISurface.h>
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <AzFramework/XcbConnectionManager.h>
#endif
namespace AZ namespace AZ
{ {
namespace Vulkan namespace Vulkan
@ -21,7 +25,7 @@ namespace AZ
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
xcb_connection_t* xcb_connection = nullptr; xcb_connection_t* xcb_connection = nullptr;
if (auto xcbConnectionManager = AzFramework::LinuxXcbConnectionManagerInterface::Get(); if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get();
xcbConnectionManager != nullptr) xcbConnectionManager != nullptr)
{ {
xcb_connection = xcbConnectionManager->GetXcbConnection(); xcb_connection = xcbConnectionManager->GetXcbConnection();

Loading…
Cancel
Save