summaryrefslogtreecommitdiffstats
path: root/xbmc/windowing/win10
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
commitc04dcc2e7d834218ef2d4194331e383402495ae1 (patch)
tree7333e38d10d75386e60f336b80c2443c1166031d /xbmc/windowing/win10
parentInitial commit. (diff)
downloadkodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz
kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/windowing/win10')
-rw-r--r--xbmc/windowing/win10/CMakeLists.txt12
-rw-r--r--xbmc/windowing/win10/WinEventsWin10.cpp658
-rw-r--r--xbmc/windowing/win10/WinEventsWin10.h83
-rw-r--r--xbmc/windowing/win10/WinSystemWin10.cpp660
-rw-r--r--xbmc/windowing/win10/WinSystemWin10.h156
-rw-r--r--xbmc/windowing/win10/WinSystemWin10DX.cpp205
-rw-r--r--xbmc/windowing/win10/WinSystemWin10DX.h90
7 files changed, 1864 insertions, 0 deletions
diff --git a/xbmc/windowing/win10/CMakeLists.txt b/xbmc/windowing/win10/CMakeLists.txt
new file mode 100644
index 0000000..7e41c17
--- /dev/null
+++ b/xbmc/windowing/win10/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(SOURCES WinEventsWin10.cpp
+ WinSystemWin10.cpp
+ WinSystemWin10DX.cpp
+ ../windows/VideoSyncD3D.cpp)
+
+set(HEADERS WinEventsWin10.h
+ WinSystemWin10.h
+ WinSystemWin10DX.h
+ ../windows/VideoSyncD3D.h
+ ../windows/WinKeyMap.h)
+
+core_add_library(windowing_windowsstore)
diff --git a/xbmc/windowing/win10/WinEventsWin10.cpp b/xbmc/windowing/win10/WinEventsWin10.cpp
new file mode 100644
index 0000000..35da911
--- /dev/null
+++ b/xbmc/windowing/win10/WinEventsWin10.cpp
@@ -0,0 +1,658 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "WinEventsWin10.h"
+
+#include "GUIUserMessages.h"
+#include "ServiceBroker.h"
+#include "application/AppInboundProtocol.h"
+#include "application/Application.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "input/actions/Action.h"
+#include "input/actions/ActionIDs.h"
+#include "input/mouse/MouseStat.h"
+#include "input/touch/generic/GenericTouchInputHandler.h"
+#include "interfaces/AnnouncementManager.h"
+#include "messaging/ApplicationMessenger.h"
+#include "rendering/dx/DeviceResources.h"
+#include "rendering/dx/RenderContext.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/SystemInfo.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
+#include "windowing/windows/WinKeyMap.h"
+
+#include "platform/win10/input/RemoteControlXbox.h"
+
+#include <winrt/Windows.Devices.Input.h>
+
+namespace winrt
+{
+ using namespace Windows::Foundation;
+}
+using namespace winrt::Windows::ApplicationModel::Core;
+using namespace winrt::Windows::Devices::Input;
+using namespace winrt::Windows::Graphics::Display;
+using namespace winrt::Windows::Media;
+using namespace winrt::Windows::System;
+using namespace winrt::Windows::UI::Core;
+using namespace winrt::Windows::UI::Input;
+using namespace winrt::Windows::UI::ViewManagement;
+
+using namespace PERIPHERALS;
+
+static winrt::Point GetScreenPoint(winrt::Point point)
+{
+ auto dpi = DX::DeviceResources::Get()->GetDpi();
+ return winrt::Point(DX::ConvertDipsToPixels(point.X, dpi), DX::ConvertDipsToPixels(point.Y, dpi));
+}
+
+CWinEventsWin10::CWinEventsWin10() = default;
+CWinEventsWin10::~CWinEventsWin10() = default;
+
+void CWinEventsWin10::InitOSKeymap(void)
+{
+ KODI::WINDOWING::WINDOWS::DIB_InitOSKeymap();
+}
+
+void CWinEventsWin10::MessagePush(XBMC_Event *newEvent)
+{
+ // push input events in the queue they may init modal dialog which init
+ // deeper message loop and call the deeper MessagePump from there.
+ if ( newEvent->type == XBMC_KEYDOWN
+ || newEvent->type == XBMC_KEYUP
+ || newEvent->type == XBMC_MOUSEMOTION
+ || newEvent->type == XBMC_MOUSEBUTTONDOWN
+ || newEvent->type == XBMC_MOUSEBUTTONUP
+ || newEvent->type == XBMC_TOUCH)
+ {
+ m_events.push(*newEvent);
+ }
+ else
+ {
+ std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort();
+ if (appPort)
+ appPort->OnEvent(*newEvent);
+ }
+}
+
+bool CWinEventsWin10::MessagePump()
+{
+ bool ret = false;
+ std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort();
+
+ // processes all pending events and exits immediately
+ CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
+
+ XBMC_Event pumpEvent;
+ while (m_events.try_pop(pumpEvent))
+ {
+ if (appPort)
+ ret |= appPort->OnEvent(pumpEvent);
+
+ if (pumpEvent.type == XBMC_MOUSEBUTTONUP)
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_UNFOCUS_ALL, 0, 0, 0, 0);
+ }
+ return ret;
+}
+
+size_t CWinEventsWin10::GetQueueSize()
+{
+ return m_events.unsafe_size();
+}
+
+void CWinEventsWin10::InitEventHandlers(const CoreWindow& window)
+{
+ CWinEventsWin10::InitOSKeymap();
+
+ //window->SetPointerCapture();
+
+ // window
+ window.SizeChanged({ this, &CWinEventsWin10::OnWindowSizeChanged });
+ window.ResizeStarted({ this, &CWinEventsWin10::OnWindowResizeStarted });
+ window.ResizeCompleted({ this, &CWinEventsWin10::OnWindowResizeCompleted });
+ window.Closed({ this, &CWinEventsWin10::OnWindowClosed});
+ window.VisibilityChanged(CWinEventsWin10::OnVisibilityChanged);
+ window.Activated(CWinEventsWin10::OnWindowActivationChanged);
+ // mouse, touch and pen
+ window.PointerPressed({ this, &CWinEventsWin10::OnPointerPressed });
+ window.PointerMoved({ this, &CWinEventsWin10::OnPointerMoved });
+ window.PointerReleased({ this, &CWinEventsWin10::OnPointerReleased });
+ window.PointerExited({ this, &CWinEventsWin10::OnPointerExited });
+ window.PointerWheelChanged({ this, &CWinEventsWin10::OnPointerWheelChanged });
+ // keyboard
+ window.Dispatcher().AcceleratorKeyActivated({ this, &CWinEventsWin10::OnAcceleratorKeyActivated });
+ // display
+ DisplayInformation currentDisplayInformation = DisplayInformation::GetForCurrentView();
+ currentDisplayInformation.DpiChanged(CWinEventsWin10::OnDpiChanged);
+ currentDisplayInformation.OrientationChanged(CWinEventsWin10::OnOrientationChanged);
+ DisplayInformation::DisplayContentsInvalidated(CWinEventsWin10::OnDisplayContentsInvalidated);
+ // system
+ SystemNavigationManager sysNavManager = SystemNavigationManager::GetForCurrentView();
+ sysNavManager.BackRequested(CWinEventsWin10::OnBackRequested);
+
+ // requirement for backgroup playback
+ m_smtc = SystemMediaTransportControls::GetForCurrentView();
+ if (m_smtc)
+ {
+ m_smtc.IsPlayEnabled(true);
+ m_smtc.IsPauseEnabled(true);
+ m_smtc.IsStopEnabled(true);
+ m_smtc.IsRecordEnabled(true);
+ m_smtc.IsNextEnabled(true);
+ m_smtc.IsPreviousEnabled(true);
+ m_smtc.IsFastForwardEnabled(true);
+ m_smtc.IsRewindEnabled(true);
+ m_smtc.IsChannelUpEnabled(true);
+ m_smtc.IsChannelDownEnabled(true);
+ if (CSysInfo::GetWindowsDeviceFamily() != CSysInfo::WindowsDeviceFamily::Xbox)
+ {
+ m_smtc.ButtonPressed(CWinEventsWin10::OnSystemMediaButtonPressed);
+ }
+ m_smtc.IsEnabled(true);;
+ CServiceBroker::GetAnnouncementManager()->AddAnnouncer(this);
+ }
+ if (CSysInfo::GetWindowsDeviceFamily() == CSysInfo::WindowsDeviceFamily::Xbox)
+ {
+ m_remote = std::make_unique<CRemoteControlXbox>();
+ m_remote->Initialize();
+ }
+}
+
+void CWinEventsWin10::UpdateWindowSize()
+{
+ auto size = DX::DeviceResources::Get()->GetOutputSize();
+
+ CLog::Log(LOGDEBUG, __FUNCTION__ ": window resize event {:f} x {:f} (as:{})", size.Width,
+ size.Height,
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen ? "true"
+ : "false");
+
+ auto appView = ApplicationView::GetForCurrentView();
+ appView.SetDesiredBoundsMode(ApplicationViewBoundsMode::UseCoreWindow);
+
+ // seems app has lost FS mode it may occurs if an user use core window's button
+ if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen && !appView.IsFullScreenMode())
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = false;
+
+ XBMC_Event newEvent = {};
+ newEvent.type = XBMC_VIDEORESIZE;
+ newEvent.resize.w = size.Width;
+ newEvent.resize.h = size.Height;
+ if (g_application.GetRenderGUI() && !DX::Windowing()->IsAlteringWindow() && newEvent.resize.w > 0 && newEvent.resize.h > 0)
+ MessagePush(&newEvent);
+}
+
+void CWinEventsWin10::OnResize(float width, float height)
+{
+ CLog::Log(LOGDEBUG, __FUNCTION__": window size changed.");
+ m_logicalWidth = width;
+ m_logicalHeight = height;
+ m_bResized = true;
+
+ if (m_sizeChanging)
+ return;
+
+ HandleWindowSizeChanged();
+}
+
+// Window event handlers.
+void CWinEventsWin10::OnWindowSizeChanged(const CoreWindow&, const WindowSizeChangedEventArgs& args)
+{
+ OnResize(args.Size().Width, args.Size().Height);
+}
+
+void CWinEventsWin10::OnWindowResizeStarted(const CoreWindow& sender, const winrt::IInspectable&)
+{
+ CLog::Log(LOGDEBUG, __FUNCTION__": window resize started.");
+ m_logicalPosX = sender.Bounds().X;
+ m_logicalPosY = sender.Bounds().Y;
+ m_sizeChanging = true;
+}
+
+void CWinEventsWin10::OnWindowResizeCompleted(const CoreWindow& sender, const winrt::IInspectable&)
+{
+ CLog::Log(LOGDEBUG, __FUNCTION__": window resize completed.");
+ m_sizeChanging = false;
+
+ if (m_logicalPosX != sender.Bounds().X || m_logicalPosY != sender.Bounds().Y)
+ m_bMoved = true;
+
+ HandleWindowSizeChanged();
+}
+
+void CWinEventsWin10::HandleWindowSizeChanged()
+{
+ CLog::Log(LOGDEBUG, __FUNCTION__": window size/move handled.");
+ if (m_bMoved)
+ {
+ // it will get position from CoreWindow
+ DX::Windowing()->OnMove(0, 0);
+ }
+ if (m_bResized)
+ {
+ DX::Windowing()->OnResize(m_logicalWidth, m_logicalHeight);
+ UpdateWindowSize();
+ }
+ m_bResized = false;
+ m_bMoved = false;
+}
+
+void CWinEventsWin10::OnVisibilityChanged(const CoreWindow& sender, const VisibilityChangedEventArgs& args)
+{
+ bool active = g_application.GetRenderGUI();
+ std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort();
+ if (appPort)
+ appPort->SetRenderGUI(args.Visible());
+
+ if (g_application.GetRenderGUI() != active)
+ DX::Windowing()->NotifyAppActiveChange(g_application.GetRenderGUI());
+ CLog::Log(LOGDEBUG, __FUNCTION__ ": window is {}",
+ g_application.GetRenderGUI() ? "shown" : "hidden");
+}
+
+void CWinEventsWin10::OnWindowActivationChanged(const CoreWindow& sender, const WindowActivatedEventArgs& args)
+{
+ bool active = g_application.GetRenderGUI();
+ if (args.WindowActivationState() == CoreWindowActivationState::Deactivated)
+ {
+ std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort();
+ if (appPort)
+ appPort->SetRenderGUI(DX::Windowing()->WindowedMode());
+ }
+ else if (args.WindowActivationState() == CoreWindowActivationState::PointerActivated
+ || args.WindowActivationState() == CoreWindowActivationState::CodeActivated)
+ {
+ std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort();
+ if (appPort)
+ appPort->SetRenderGUI(true);
+ }
+ if (g_application.GetRenderGUI() != active)
+ DX::Windowing()->NotifyAppActiveChange(g_application.GetRenderGUI());
+ CLog::Log(LOGDEBUG, __FUNCTION__ ": window is {}",
+ g_application.GetRenderGUI() ? "active" : "inactive");
+}
+
+void CWinEventsWin10::OnWindowClosed(const CoreWindow& sender, const CoreWindowEventArgs& args)
+{
+ // send quit command to the application if it's still running
+ if (!g_application.m_bStop)
+ {
+ XBMC_Event newEvent = {};
+ newEvent.type = XBMC_QUIT;
+ MessagePush(&newEvent);
+ }
+}
+
+void CWinEventsWin10::OnPointerPressed(const CoreWindow&, const PointerEventArgs& args)
+{
+ XBMC_Event newEvent = {};
+
+ PointerPoint point = args.CurrentPoint();
+ auto position = GetScreenPoint(point.Position());
+
+ if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Touch)
+ {
+ CGenericTouchInputHandler::GetInstance().HandleTouchInput(TouchInputDown, position.X, position.Y, point.Timestamp(), 0, 10);
+ return;
+ }
+ else
+ {
+ newEvent.type = XBMC_MOUSEBUTTONDOWN;
+ newEvent.button.x = position.X;
+ newEvent.button.y = position.Y;
+ if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Mouse)
+ {
+ if (point.Properties().IsLeftButtonPressed())
+ newEvent.button.button = XBMC_BUTTON_LEFT;
+ else if (point.Properties().IsMiddleButtonPressed())
+ newEvent.button.button = XBMC_BUTTON_MIDDLE;
+ else if (point.Properties().IsRightButtonPressed())
+ newEvent.button.button = XBMC_BUTTON_RIGHT;
+ }
+ else if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Pen)
+ {
+ // pen
+ // TODO
+ }
+ }
+ MessagePush(&newEvent);
+}
+
+void CWinEventsWin10::OnPointerMoved(const CoreWindow&, const PointerEventArgs& args)
+{
+ PointerPoint point = args.CurrentPoint();
+ auto position = GetScreenPoint(point.Position());
+
+ if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Touch)
+ {
+ if (point.IsInContact())
+ {
+ CGenericTouchInputHandler::GetInstance().UpdateTouchPointer(0, position.X, position.Y, point.Timestamp(), 10.f);
+ CGenericTouchInputHandler::GetInstance().HandleTouchInput(TouchInputMove, position.X, position.Y, point.Timestamp(), 0, 10.f);
+ }
+ return;
+ }
+
+ XBMC_Event newEvent = {};
+ newEvent.type = XBMC_MOUSEMOTION;
+ newEvent.motion.x = position.X;
+ newEvent.motion.y = position.Y;
+ MessagePush(&newEvent);
+}
+
+void CWinEventsWin10::OnPointerReleased(const CoreWindow&, const PointerEventArgs& args)
+{
+ PointerPoint point = args.CurrentPoint();
+ auto position = GetScreenPoint(point.Position());
+
+ if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Touch)
+ {
+ CGenericTouchInputHandler::GetInstance().HandleTouchInput(TouchInputUp, position.X, position.Y, point.Timestamp(), 0, 10);
+ return;
+ }
+
+ XBMC_Event newEvent = {};
+ newEvent.type = XBMC_MOUSEBUTTONUP;
+ newEvent.button.x = position.X;
+ newEvent.button.y = position.Y;
+
+ if (point.Properties().PointerUpdateKind() == PointerUpdateKind::LeftButtonReleased)
+ newEvent.button.button = XBMC_BUTTON_LEFT;
+ else if (point.Properties().PointerUpdateKind() == PointerUpdateKind::MiddleButtonReleased)
+ newEvent.button.button = XBMC_BUTTON_MIDDLE;
+ else if (point.Properties().PointerUpdateKind() == PointerUpdateKind::RightButtonReleased)
+ newEvent.button.button = XBMC_BUTTON_RIGHT;
+
+ MessagePush(&newEvent);
+}
+
+void CWinEventsWin10::OnPointerExited(const CoreWindow&, const PointerEventArgs& args)
+{
+ const PointerPoint& point = args.CurrentPoint();
+ auto position = GetScreenPoint(point.Position());
+
+ if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Touch)
+ {
+ CGenericTouchInputHandler::GetInstance().HandleTouchInput(TouchInputAbort, position.X, position.Y, point.Timestamp(), 0, 10);
+ }
+}
+
+void CWinEventsWin10::OnPointerWheelChanged(const CoreWindow&, const PointerEventArgs& args)
+{
+ XBMC_Event newEvent = {};
+ newEvent.type = XBMC_MOUSEBUTTONDOWN;
+ newEvent.button.x = args.CurrentPoint().Position().X;
+ newEvent.button.y = args.CurrentPoint().Position().Y;
+ newEvent.button.button = args.CurrentPoint().Properties().MouseWheelDelta() > 0 ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN;
+ MessagePush(&newEvent);
+ newEvent.type = XBMC_MOUSEBUTTONUP;
+ MessagePush(&newEvent);
+}
+
+void CWinEventsWin10::Kodi_KeyEvent(unsigned int vkey, unsigned scancode, unsigned keycode, bool isDown)
+{
+ using State = CoreVirtualKeyStates;
+
+ XBMC_keysym keysym = {};
+ keysym.scancode = scancode;
+ keysym.sym = KODI::WINDOWING::WINDOWS::VK_keymap[vkey];
+ keysym.unicode = keycode;
+
+ auto window = CoreWindow::GetForCurrentThread();
+
+ uint16_t mod = (uint16_t)XBMCKMOD_NONE;
+ // If left control and right alt are down this usually means that AltGr is down
+ if ((window.GetKeyState(VirtualKey::LeftControl) & State::Down) == State::Down
+ && (window.GetKeyState(VirtualKey::RightMenu) & State::Down) == State::Down)
+ {
+ mod |= XBMCKMOD_MODE;
+ mod |= XBMCKMOD_MODE;
+ }
+ else
+ {
+ if ((window.GetKeyState(VirtualKey::LeftControl) & State::Down) == State::Down)
+ mod |= XBMCKMOD_LCTRL;
+ if ((window.GetKeyState(VirtualKey::RightMenu) & State::Down) == State::Down)
+ mod |= XBMCKMOD_RALT;
+ }
+
+ // Check the remaining modifiers
+ if ((window.GetKeyState(VirtualKey::LeftShift) & State::Down) == State::Down)
+ mod |= XBMCKMOD_LSHIFT;
+ if ((window.GetKeyState(VirtualKey::RightShift) & State::Down) == State::Down)
+ mod |= XBMCKMOD_RSHIFT;
+ if ((window.GetKeyState(VirtualKey::RightControl) & State::Down) == State::Down)
+ mod |= XBMCKMOD_RCTRL;
+ if ((window.GetKeyState(VirtualKey::LeftMenu) & State::Down) == State::Down)
+ mod |= XBMCKMOD_LALT;
+ if ((window.GetKeyState(VirtualKey::LeftWindows) & State::Down) == State::Down)
+ mod |= XBMCKMOD_LSUPER;
+ if ((window.GetKeyState(VirtualKey::RightWindows) & State::Down) == State::Down)
+ mod |= XBMCKMOD_LSUPER;
+
+ keysym.mod = static_cast<XBMCMod>(mod);
+
+ XBMC_Event newEvent = {};
+ newEvent.type = isDown ? XBMC_KEYDOWN : XBMC_KEYUP;
+ newEvent.key.keysym = keysym;
+ MessagePush(&newEvent);
+}
+
+void CWinEventsWin10::OnAcceleratorKeyActivated(const CoreDispatcher&, const AcceleratorKeyEventArgs& args)
+{
+ static auto lockedState = CoreVirtualKeyStates::Locked;
+ static VirtualKey keyStore = VirtualKey::None;
+
+ // skip if device is remote control
+ if (m_remote && m_remote->IsRemoteDevice(args.DeviceId().c_str()))
+ return;
+
+ bool isDown = false;
+ unsigned keyCode = 0;
+ unsigned vk = static_cast<unsigned>(args.VirtualKey());
+
+ auto window = CoreWindow::GetForCurrentThread();
+ bool numLockLocked = ((window.GetKeyState(VirtualKey::NumberKeyLock) & lockedState) == lockedState);
+
+ switch (args.EventType())
+ {
+ case CoreAcceleratorKeyEventType::KeyDown:
+ case CoreAcceleratorKeyEventType::SystemKeyDown:
+ {
+ if ( (vk == 0x08) // VK_BACK
+ || (vk == 0x09) // VK_TAB
+ || (vk == 0x0C) // VK_CLEAR
+ || (vk == 0x0D) // VK_RETURN
+ || (vk == 0x1B) // VK_ESCAPE
+ || (vk == 0x20) // VK_SPACE
+ || (vk >= 0x30 && vk <= 0x39) // numeric keys
+ || (vk >= 0x41 && vk <= 0x5A) // alphabetic keys
+ || (vk >= 0x60 && vk <= 0x69 && numLockLocked) // keypad numeric (if numlock is on)
+ || (vk >= 0x6A && vk <= 0x6F) // keypad keys except numeric
+ || (vk >= 0x92 && vk <= 0x96) // OEM specific
+ || (vk >= 0xBA && vk <= 0xC0) // OEM specific
+ || (vk >= 0xDB && vk <= 0xDF) // OEM specific
+ || (vk >= 0xE1 && vk <= 0xF5 && vk != 0xE5 && vk != 0xE7 && vk != 0xE8) // OEM specific
+ )
+ {
+ // store this for character events, because VirtualKey is key code on character event.
+ keyStore = args.VirtualKey();
+ return;
+ }
+ isDown = true;
+ break;
+ }
+ case CoreAcceleratorKeyEventType::KeyUp:
+ case CoreAcceleratorKeyEventType::SystemKeyUp:
+ break;
+ case CoreAcceleratorKeyEventType::Character:
+ case CoreAcceleratorKeyEventType::SystemCharacter:
+ case CoreAcceleratorKeyEventType::UnicodeCharacter:
+ case CoreAcceleratorKeyEventType::DeadCharacter:
+ case CoreAcceleratorKeyEventType::SystemDeadCharacter:
+ {
+ // VirtualKey is KeyCode
+ keyCode = static_cast<unsigned>(args.VirtualKey());
+ // rewrite vk with stored value
+ vk = static_cast<unsigned>(keyStore);
+ // reset stored value
+ keyStore = VirtualKey::None;
+ isDown = true;
+ }
+ default:
+ break;
+ }
+
+ Kodi_KeyEvent(vk, args.KeyStatus().ScanCode, keyCode, isDown);
+ args.Handled(true);
+}
+
+// DisplayInformation event handlers.
+void CWinEventsWin10::OnDpiChanged(const DisplayInformation& sender, const winrt::IInspectable&)
+{
+ // Note: The value for LogicalDpi retrieved here may not match the effective DPI of the app
+ // if it is being scaled for high resolution devices. Once the DPI is set on DeviceResources,
+ // you should always retrieve it using the GetDpi method.
+ // See DeviceResources.cpp for more details.
+ //critical_section::scoped_lock lock(m_deviceResources->GetCriticalSection());
+ RECT resizeRect = { 0,0,0,0 };
+ DX::Windowing()->DPIChanged(sender.LogicalDpi(), resizeRect);
+ CGenericTouchInputHandler::GetInstance().SetScreenDPI(DX::DisplayMetrics::Dpi100);
+}
+
+void CWinEventsWin10::OnOrientationChanged(const DisplayInformation&, const winrt::IInspectable&)
+{
+ //critical_section::scoped_lock lock(m_deviceResources->GetCriticalSection());
+ //m_deviceResources->SetCurrentOrientation(sender->CurrentOrientation);
+
+ //auto size = DX::DeviceResources::Get()->GetOutputSize();
+ //UpdateWindowSize(size.Width, size.Height);
+}
+
+void CWinEventsWin10::OnDisplayContentsInvalidated(const DisplayInformation&, const winrt::IInspectable&)
+{
+ CLog::Log(LOGDEBUG, __FUNCTION__": onevent.");
+ DX::DeviceResources::Get()->ValidateDevice();
+}
+
+void CWinEventsWin10::OnBackRequested(const winrt::IInspectable&, const BackRequestedEventArgs& args)
+{
+ // handle this only on windows mobile
+ if (CSysInfo::GetWindowsDeviceFamily() == CSysInfo::WindowsDeviceFamily::Mobile)
+ {
+ CServiceBroker::GetAppMessenger()->PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1,
+ static_cast<void*>(new CAction(ACTION_NAV_BACK)));
+ }
+ args.Handled(true);
+}
+
+void CWinEventsWin10::OnSystemMediaButtonPressed(const SystemMediaTransportControls&, const SystemMediaTransportControlsButtonPressedEventArgs& args)
+{
+ int action = ACTION_NONE;
+ switch (args.Button())
+ {
+ case SystemMediaTransportControlsButton::ChannelDown:
+ action = ACTION_CHANNEL_DOWN;
+ break;
+ case SystemMediaTransportControlsButton::ChannelUp:
+ action = ACTION_CHANNEL_UP;
+ break;
+ case SystemMediaTransportControlsButton::FastForward:
+ action = ACTION_PLAYER_FORWARD;
+ break;
+ case SystemMediaTransportControlsButton::Rewind:
+ action = ACTION_PLAYER_REWIND;
+ break;
+ case SystemMediaTransportControlsButton::Next:
+ action = ACTION_NEXT_ITEM;
+ break;
+ case SystemMediaTransportControlsButton::Previous:
+ action = ACTION_PREV_ITEM;
+ break;
+ case SystemMediaTransportControlsButton::Pause:
+ case SystemMediaTransportControlsButton::Play:
+ action = ACTION_PLAYER_PLAYPAUSE;
+ break;
+ case SystemMediaTransportControlsButton::Stop:
+ action = ACTION_STOP;
+ break;
+ case SystemMediaTransportControlsButton::Record:
+ action = ACTION_RECORD;
+ break;
+ default:
+ break;
+ }
+ if (action != ACTION_NONE)
+ {
+ CServiceBroker::GetAppMessenger()->PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1,
+ static_cast<void*>(new CAction(action)));
+ }
+}
+
+void CWinEventsWin10::Announce(ANNOUNCEMENT::AnnouncementFlag flag,
+ const std::string& sender,
+ const std::string& message,
+ const CVariant& data)
+{
+ if (flag & ANNOUNCEMENT::Player)
+ {
+ double speed = 1.0;
+ if (data.isMember("player") && data["player"].isMember("speed"))
+ speed = data["player"]["speed"].asDouble(1.0);
+
+ bool changed = false;
+ MediaPlaybackStatus status = MediaPlaybackStatus::Changing;
+
+ if (message == "OnPlay" || message == "OnResume")
+ {
+ changed = true;
+ status = MediaPlaybackStatus::Playing;
+ }
+ else if (message == "OnStop")
+ {
+ changed = true;
+ status = MediaPlaybackStatus::Stopped;
+ }
+ else if (message == "OnPause")
+ {
+ changed = true;
+ status = MediaPlaybackStatus::Paused;
+ }
+ else if (message == "OnSpeedChanged")
+ {
+ changed = true;
+ status = speed != 0.0 ? MediaPlaybackStatus::Playing : MediaPlaybackStatus::Paused;
+ }
+
+ if (changed)
+ {
+ try
+ {
+ auto dispatcher = CoreApplication::MainView().Dispatcher();
+ if (dispatcher)
+ {
+ dispatcher.RunAsync(CoreDispatcherPriority::Normal, DispatchedHandler([status, speed]
+ {
+ auto smtc = SystemMediaTransportControls::GetForCurrentView();
+ if (!smtc)
+ return;
+
+ smtc.PlaybackStatus(status);
+ smtc.PlaybackRate(speed);
+ }));
+ }
+ }
+ catch (const winrt::hresult_error&)
+ {
+ }
+ }
+ }
+}
diff --git a/xbmc/windowing/win10/WinEventsWin10.h b/xbmc/windowing/win10/WinEventsWin10.h
new file mode 100644
index 0000000..c4bd345
--- /dev/null
+++ b/xbmc/windowing/win10/WinEventsWin10.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "interfaces/IAnnouncer.h"
+#include "windowing/WinEvents.h"
+
+#include <concurrent_queue.h>
+#include <winrt/Windows.Media.h>
+
+class CRemoteControlXbox;
+
+class CWinEventsWin10 : public IWinEvents
+ , public ANNOUNCEMENT::IAnnouncer
+{
+public:
+ CWinEventsWin10();
+ virtual ~CWinEventsWin10();
+
+ void MessagePush(XBMC_Event *newEvent);
+ bool MessagePump() override;
+ virtual size_t GetQueueSize();
+
+ // initialization
+ void InitEventHandlers(const winrt::Windows::UI::Core::CoreWindow&);
+ static void InitOSKeymap(void);
+
+ // Window event handlers.
+ void OnWindowSizeChanged(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::UI::Core::WindowSizeChangedEventArgs&);
+ void OnWindowResizeStarted(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::Foundation::IInspectable&);
+ void OnWindowResizeCompleted(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::Foundation::IInspectable&);
+ void OnWindowClosed(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::UI::Core::CoreWindowEventArgs&);
+ static void OnWindowActivationChanged(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::UI::Core::WindowActivatedEventArgs&);
+ static void OnVisibilityChanged(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::UI::Core::VisibilityChangedEventArgs&);
+ // touch mouse and pen
+ void OnPointerPressed(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::UI::Core::PointerEventArgs&);
+ void OnPointerMoved(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::UI::Core::PointerEventArgs&);
+ void OnPointerReleased(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::UI::Core::PointerEventArgs&);
+ void OnPointerExited(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::UI::Core::PointerEventArgs&);
+ void OnPointerWheelChanged(const winrt::Windows::UI::Core::CoreWindow&, const winrt::Windows::UI::Core::PointerEventArgs&);
+ // keyboard
+ void OnAcceleratorKeyActivated(const winrt::Windows::UI::Core::CoreDispatcher&, const winrt::Windows::UI::Core::AcceleratorKeyEventArgs&);
+
+ // DisplayInformation event handlers.
+ static void OnDpiChanged(const winrt::Windows::Graphics::Display::DisplayInformation&, const winrt::Windows::Foundation::IInspectable&);
+ static void OnOrientationChanged(const winrt::Windows::Graphics::Display::DisplayInformation&, const winrt::Windows::Foundation::IInspectable&);
+ static void OnDisplayContentsInvalidated(const winrt::Windows::Graphics::Display::DisplayInformation&, const winrt::Windows::Foundation::IInspectable&);
+ // system
+ static void OnBackRequested(const winrt::Windows::Foundation::IInspectable&, const winrt::Windows::UI::Core::BackRequestedEventArgs&);
+ // system media handlers
+ static void OnSystemMediaButtonPressed(const winrt::Windows::Media::SystemMediaTransportControls&
+ , const winrt::Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs&);
+ // IAnnouncer overrides
+ void Announce(ANNOUNCEMENT::AnnouncementFlag flag,
+ const std::string& sender,
+ const std::string& message,
+ const CVariant& data) override;
+
+private:
+ friend class CWinSystemWin10;
+
+ void OnResize(float width, float height);
+ void UpdateWindowSize();
+ void Kodi_KeyEvent(unsigned int vkey, unsigned scancode, unsigned keycode, bool isDown);
+ void HandleWindowSizeChanged();
+
+ Concurrency::concurrent_queue<XBMC_Event> m_events;
+ winrt::Windows::Media::SystemMediaTransportControls m_smtc{ nullptr };
+ bool m_bResized{ false };
+ bool m_bMoved{ false };
+ bool m_sizeChanging{ false };
+ float m_logicalWidth{ 0 };
+ float m_logicalHeight{ 0 };
+ float m_logicalPosX{ 0 };
+ float m_logicalPosY{ 0 };
+ std::unique_ptr<CRemoteControlXbox> m_remote;
+};
diff --git a/xbmc/windowing/win10/WinSystemWin10.cpp b/xbmc/windowing/win10/WinSystemWin10.cpp
new file mode 100644
index 0000000..6de3f78
--- /dev/null
+++ b/xbmc/windowing/win10/WinSystemWin10.cpp
@@ -0,0 +1,660 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "WinSystemWin10.h"
+
+#include "ServiceBroker.h"
+#include "WinEventsWin10.h"
+#include "application/Application.h"
+#include "cores/AudioEngine/AESinkFactory.h"
+#include "cores/AudioEngine/Sinks/AESinkWASAPI.h"
+#include "cores/AudioEngine/Sinks/AESinkXAudio.h"
+#include "rendering/dx/DirectXHelper.h"
+#include "rendering/dx/RenderContext.h"
+#include "rendering/dx/ScreenshotSurfaceWindows.h"
+#include "settings/DisplaySettings.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/SystemInfo.h"
+#include "utils/log.h"
+#include "windowing/GraphicContext.h"
+#include "windowing/windows/VideoSyncD3D.h"
+
+#include "platform/win10/AsyncHelpers.h"
+#include "platform/win32/CharsetConverter.h"
+
+#include <mutex>
+
+#pragma pack(push,8)
+
+#include <tpcshrd.h>
+#include <ppltasks.h>
+#include <winrt/Windows.ApplicationModel.DataTransfer.h>
+#include <winrt/Windows.Foundation.Metadata.h>
+#include <winrt/Windows.Graphics.Display.h>
+#include <winrt/Windows.Graphics.Display.Core.h>
+
+using namespace winrt::Windows::ApplicationModel::DataTransfer;
+using namespace winrt::Windows::Foundation::Metadata;
+using namespace winrt::Windows::Graphics::Display;
+using namespace winrt::Windows::Graphics::Display::Core;
+using namespace winrt::Windows::UI::Core;
+using namespace winrt::Windows::UI::ViewManagement;
+
+using namespace std::chrono_literals;
+
+CWinSystemWin10::CWinSystemWin10()
+ : CWinSystemBase()
+ , m_ValidWindowedPosition(false)
+ , m_IsAlteringWindow(false)
+ , m_delayDispReset(false)
+ , m_state(WINDOW_STATE_WINDOWED)
+ , m_fullscreenState(WINDOW_FULLSCREEN_STATE_FULLSCREEN_WINDOW)
+ , m_windowState(WINDOW_WINDOW_STATE_WINDOWED)
+ , m_inFocus(false)
+ , m_bMinimized(false)
+{
+ m_winEvents.reset(new CWinEventsWin10());
+
+ AE::CAESinkFactory::ClearSinks();
+ CAESinkXAudio::Register();
+ CAESinkWASAPI::Register();
+ CScreenshotSurfaceWindows::Register();
+}
+
+CWinSystemWin10::~CWinSystemWin10()
+{
+};
+
+bool CWinSystemWin10::InitWindowSystem()
+{
+ m_coreWindow = CoreWindow::GetForCurrentThread();
+ dynamic_cast<CWinEventsWin10&>(*m_winEvents).InitEventHandlers(m_coreWindow);
+
+ if (!CWinSystemBase::InitWindowSystem())
+ return false;
+
+ if (m_displays.empty())
+ {
+ CLog::Log(LOGERROR, "{} - no suitable monitor found, aborting...", __FUNCTION__);
+ return false;
+ }
+
+ return true;
+}
+
+bool CWinSystemWin10::DestroyWindowSystem()
+{
+ m_bWindowCreated = false;
+ RestoreDesktopResolution();
+ return true;
+}
+
+bool CWinSystemWin10::CanDoWindowed()
+{
+ return CSysInfo::GetWindowsDeviceFamily() == CSysInfo::Desktop;
+}
+
+bool CWinSystemWin10::CreateNewWindow(const std::string& name, bool fullScreen, RESOLUTION_INFO& res)
+{
+ UpdateStates(fullScreen);
+ // initialize the state
+ WINDOW_STATE state = GetState(fullScreen);
+
+ m_nWidth = res.iWidth;
+ m_nHeight = res.iHeight;
+ m_bFullScreen = fullScreen;
+ m_fRefreshRate = res.fRefreshRate;
+ m_inFocus = true;
+ m_bWindowCreated = true;
+ m_state = state;
+
+ m_coreWindow.Activate();
+
+ AdjustWindow();
+ // dispatch all events currently pending in the queue to show window's content
+ // and hide UWP splash, without this the Kodi's splash will not be shown
+ m_coreWindow.Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
+
+ return true;
+}
+
+bool CWinSystemWin10::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
+{
+ m_nWidth = newWidth;
+ m_nHeight = newHeight;
+
+ if (newLeft > 0)
+ m_nLeft = newLeft;
+
+ if (newTop > 0)
+ m_nTop = newTop;
+
+ AdjustWindow();
+
+ return true;
+}
+
+void CWinSystemWin10::FinishWindowResize(int newWidth, int newHeight)
+{
+ m_nWidth = newWidth;
+ m_nHeight = newHeight;
+
+ float dpi = DX::DeviceResources::Get()->GetDpi();
+ int dipsWidth = round(DX::ConvertPixelsToDips(m_nWidth, dpi));
+ int dipsHeight = round(DX::ConvertPixelsToDips(m_nHeight, dpi));
+
+ ApplicationView::PreferredLaunchViewSize(winrt::Windows::Foundation::Size(dipsWidth, dipsHeight));
+ ApplicationView::PreferredLaunchWindowingMode(ApplicationViewWindowingMode::PreferredLaunchViewSize);
+}
+
+void CWinSystemWin10::AdjustWindow()
+{
+ CLog::Log(LOGDEBUG, __FUNCTION__": adjusting window if required.");
+
+ auto appView = ApplicationView::GetForCurrentView();
+ bool isInFullscreen = appView.IsFullScreenMode();
+
+ if (m_state == WINDOW_STATE_FULLSCREEN_WINDOW || m_state == WINDOW_STATE_FULLSCREEN)
+ {
+ if (!isInFullscreen)
+ {
+ if (appView.TryEnterFullScreenMode())
+ ApplicationView::PreferredLaunchWindowingMode(ApplicationViewWindowingMode::FullScreen);
+ }
+ }
+ else // m_state == WINDOW_STATE_WINDOWED
+ {
+ if (isInFullscreen)
+ {
+ appView.ExitFullScreenMode();
+ }
+
+ int viewWidth = appView.VisibleBounds().Width;
+ int viewHeight = appView.VisibleBounds().Height;
+
+ float dpi = DX::DeviceResources::Get()->GetDpi();
+ int dipsWidth = round(DX::ConvertPixelsToDips(m_nWidth, dpi));
+ int dipsHeight = round(DX::ConvertPixelsToDips(m_nHeight, dpi));
+
+ if (viewHeight != dipsHeight || viewWidth != dipsWidth)
+ {
+ if (!appView.TryResizeView(winrt::Windows::Foundation::Size(dipsWidth, dipsHeight)))
+ {
+ CLog::LogF(LOGDEBUG, __FUNCTION__, "resizing ApplicationView failed.");
+ }
+ }
+
+ ApplicationView::PreferredLaunchViewSize(winrt::Windows::Foundation::Size(dipsWidth, dipsHeight));
+ ApplicationView::PreferredLaunchWindowingMode(ApplicationViewWindowingMode::PreferredLaunchViewSize);
+ }
+}
+
+bool CWinSystemWin10::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
+{
+ CWinSystemWin10::UpdateStates(fullScreen);
+ WINDOW_STATE state = GetState(fullScreen);
+
+ CLog::Log(LOGDEBUG, "{} ({}) with size {}x{}, refresh {:f}{}", __FUNCTION__,
+ window_state_names[state], res.iWidth, res.iHeight, res.fRefreshRate,
+ (res.dwFlags & D3DPRESENTFLAG_INTERLACED) ? "i" : "");
+
+ bool forceChange = false; // resolution/display is changed but window state isn't changed
+ bool stereoChange = IsStereoEnabled() != (CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode() == RENDER_STEREO_MODE_HARDWAREBASED);
+
+ if ( m_nWidth != res.iWidth || m_nHeight != res.iHeight || m_fRefreshRate != res.fRefreshRate ||
+ stereoChange || m_bFirstResChange)
+ {
+ forceChange = true;
+ }
+
+ if (state == m_state && !forceChange)
+ return true;
+
+ // entering to stereo mode, limit resolution to 1080p@23.976
+ if (stereoChange && !IsStereoEnabled() && res.iWidth > 1280)
+ {
+ res = CDisplaySettings::GetInstance().GetResolutionInfo(CResolutionUtils::ChooseBestResolution(24.f / 1.001f, 1920, 1080, true));
+ }
+
+ if (m_state == WINDOW_STATE_WINDOWED)
+ {
+ if (m_coreWindow)
+ {
+ m_nLeft = m_coreWindow.Bounds().X;
+ m_nTop = m_coreWindow.Bounds().Y;
+ m_ValidWindowedPosition = true;
+ }
+ }
+
+ m_IsAlteringWindow = true;
+ ReleaseBackBuffer();
+
+ m_bFirstResChange = false;
+ m_bFullScreen = fullScreen;
+ m_nWidth = res.iWidth;
+ m_nHeight = res.iHeight;
+ m_bBlankOtherDisplay = blankOtherDisplays;
+ m_fRefreshRate = res.fRefreshRate;
+
+ if (state == WINDOW_STATE_FULLSCREEN)
+ {
+ // isn't allowed in UWP
+ }
+ else if (m_state == WINDOW_STATE_FULLSCREEN || m_state == WINDOW_STATE_FULLSCREEN_WINDOW) // we're in fullscreen state now
+ {
+ if (state == WINDOW_STATE_WINDOWED) // go to a windowed state
+ {
+ // need to restore resolution if it was changed to not native
+ // because we do not support resolution change in windowed mode
+ RestoreDesktopResolution();
+ }
+ else if (state == WINDOW_STATE_FULLSCREEN_WINDOW) // enter fullscreen window instead
+ {
+ ChangeResolution(res, stereoChange);
+ }
+
+ m_state = state;
+ AdjustWindow();
+ }
+ else // we're in windowed state now
+ {
+ if (state == WINDOW_STATE_FULLSCREEN_WINDOW)
+ {
+ ChangeResolution(res, stereoChange);
+
+ m_state = state;
+ AdjustWindow();
+ }
+ }
+
+ CreateBackBuffer();
+ m_IsAlteringWindow = false;
+ return true;
+}
+
+bool CWinSystemWin10::DPIChanged(WORD dpi, RECT windowRect) const
+{
+ (void)dpi;
+ return true;
+}
+
+void CWinSystemWin10::RestoreDesktopResolution()
+{
+ CLog::Log(LOGDEBUG, __FUNCTION__": restoring default desktop resolution");
+ ChangeResolution(CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP));
+}
+
+const MONITOR_DETAILS* CWinSystemWin10::GetDefaultMonitor() const
+{
+ if (m_displays.empty())
+ return nullptr;
+
+ return &m_displays.front();
+}
+
+bool CWinSystemWin10::ChangeResolution(const RESOLUTION_INFO& res, bool forceChange /*= false*/)
+{
+ const MONITOR_DETAILS* details = GetDefaultMonitor();
+
+ if (!details)
+ return false;
+
+ if (ApiInformation::IsTypePresent(L"Windows.Graphics.Display.Core.HdmiDisplayInformation"))
+ {
+ bool changed = false;
+ auto hdmiInfo = HdmiDisplayInformation::GetForCurrentView();
+ if (hdmiInfo != nullptr)
+ {
+ // default mode not in list of supported display modes
+ if (res.iScreenWidth == details->ScreenWidth && res.iScreenHeight == details->ScreenHeight
+ && fabs(res.fRefreshRate - details->RefreshRate) <= 0.00001)
+ {
+ Wait(hdmiInfo.SetDefaultDisplayModeAsync());
+ changed = true;
+ }
+ else
+ {
+ bool needStereo = CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode() == RENDER_STEREO_MODE_HARDWAREBASED;
+ auto hdmiModes = hdmiInfo.GetSupportedDisplayModes();
+
+ HdmiDisplayMode selected = nullptr;
+ for (const auto& mode : hdmiModes)
+ {
+ if (res.iScreenWidth == mode.ResolutionWidthInRawPixels() && res.iScreenHeight == mode.ResolutionHeightInRawPixels()
+ && fabs(res.fRefreshRate - mode.RefreshRate()) <= 0.00001)
+ {
+ selected = mode;
+ if (needStereo == mode.StereoEnabled())
+ break;
+ }
+ }
+
+ if (selected != nullptr)
+ {
+ changed = Wait(hdmiInfo.RequestSetCurrentDisplayModeAsync(selected));
+ }
+ }
+ }
+
+ // changing display mode doesn't fire CoreWindow::SizeChanged event
+ if (changed && m_bWindowCreated)
+ {
+ // dispatch all events currently pending in the queue to change window's content
+ m_coreWindow.Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
+
+ float dpi = DisplayInformation::GetForCurrentView().LogicalDpi();
+ float dipsW = DX::ConvertPixelsToDips(m_nWidth, dpi);
+ float dipsH = DX::ConvertPixelsToDips(m_nHeight, dpi);
+
+ dynamic_cast<CWinEventsWin10&>(*m_winEvents).OnResize(dipsW, dipsH);
+ }
+ return changed;
+ }
+
+ CLog::LogF(LOGDEBUG, "Not supported.");
+ return false;
+}
+
+void CWinSystemWin10::UpdateResolutions()
+{
+ m_displays.clear();
+
+ CWinSystemBase::UpdateResolutions();
+ GetConnectedDisplays(m_displays);
+
+ const MONITOR_DETAILS* details = GetDefaultMonitor();
+ if (!details)
+ return;
+
+ float refreshRate;
+ int w = details->ScreenWidth;
+ int h = details->ScreenHeight;
+ uint32_t dwFlags = details->Interlaced ? D3DPRESENTFLAG_INTERLACED : 0;;
+
+ if (details->RefreshRate == 59 || details->RefreshRate == 29 || details->RefreshRate == 23)
+ refreshRate = static_cast<float>(details->RefreshRate + 1) / 1.001f;
+ else
+ refreshRate = static_cast<float>(details->RefreshRate);
+
+ RESOLUTION_INFO& primary_info = CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP);
+ UpdateDesktopResolution(primary_info, "Default", w, h, refreshRate, dwFlags);
+ CLog::Log(LOGINFO, "Primary mode: {}", primary_info.strMode);
+
+ // erase previous stored modes
+ CDisplaySettings::GetInstance().ClearCustomResolutions();
+
+ if (ApiInformation::IsTypePresent(L"Windows.Graphics.Display.Core.HdmiDisplayInformation"))
+ {
+ auto hdmiInfo = HdmiDisplayInformation::GetForCurrentView();
+ if (hdmiInfo != nullptr)
+ {
+ auto hdmiModes = hdmiInfo.GetSupportedDisplayModes();
+ for (const auto& mode : hdmiModes)
+ {
+ RESOLUTION_INFO res;
+ res.iWidth = mode.ResolutionWidthInRawPixels();
+ res.iHeight = mode.ResolutionHeightInRawPixels();
+ res.bFullScreen = true;
+ res.dwFlags = 0;
+ res.fRefreshRate = mode.RefreshRate();
+ res.fPixelRatio = 1.0f;
+ res.iScreenWidth = res.iWidth;
+ res.iScreenHeight = res.iHeight;
+ res.iSubtitles = res.iHeight;
+ res.strMode = StringUtils::Format("Default: {}x{} @ {:.2f}Hz", res.iWidth, res.iHeight,
+ res.fRefreshRate);
+ GetGfxContext().ResetOverscan(res);
+
+ if (AddResolution(res))
+ CLog::Log(LOGINFO, "Additional mode: {} {}", res.strMode,
+ mode.Is2086MetadataSupported() ? "(HDR)" : "");
+ }
+ }
+ }
+
+ CDisplaySettings::GetInstance().ApplyCalibrations();
+}
+
+bool CWinSystemWin10::AddResolution(const RESOLUTION_INFO &res)
+{
+ for (unsigned int i = RES_CUSTOM; i < CDisplaySettings::GetInstance().ResolutionInfoSize(); i++)
+ {
+ RESOLUTION_INFO& info = CDisplaySettings::GetInstance().GetResolutionInfo(i);
+ if ( info.iWidth == res.iWidth
+ && info.iHeight == res.iHeight
+ && info.iScreenWidth == res.iScreenWidth
+ && info.iScreenHeight == res.iScreenHeight
+ && info.fRefreshRate == res.fRefreshRate
+ && info.dwFlags == res.dwFlags)
+ return false; // already have this resolution
+ }
+
+ CDisplaySettings::GetInstance().AddResolutionInfo(res);
+ return true;
+}
+
+void CWinSystemWin10::GetConnectedDisplays(std::vector<MONITOR_DETAILS>& outputs)
+{
+ auto dispatcher = m_coreWindow.Dispatcher();
+ DispatchedHandler handler([&]()
+ {
+ MONITOR_DETAILS md = {};
+
+ auto displayInfo = DisplayInformation::GetForCurrentView();
+ bool flipResolution = false;
+ switch (displayInfo.NativeOrientation())
+ {
+ case DisplayOrientations::Landscape:
+ switch (displayInfo.CurrentOrientation())
+ {
+ case DisplayOrientations::Portrait:
+ case DisplayOrientations::PortraitFlipped:
+ flipResolution = true;
+ break;
+ }
+ break;
+ case DisplayOrientations::Portrait:
+ switch (displayInfo.CurrentOrientation())
+ {
+ case DisplayOrientations::Landscape:
+ case DisplayOrientations::LandscapeFlipped:
+ flipResolution = true;
+ break;
+ }
+ break;
+ }
+ md.ScreenWidth = flipResolution ? displayInfo.ScreenHeightInRawPixels() : displayInfo.ScreenWidthInRawPixels();
+ md.ScreenHeight = flipResolution ? displayInfo.ScreenWidthInRawPixels() : displayInfo.ScreenHeightInRawPixels();
+
+ if (ApiInformation::IsTypePresent(L"Windows.Graphics.Display.Core.HdmiDisplayInformation"))
+ {
+ auto hdmiInfo = HdmiDisplayInformation::GetForCurrentView();
+ if (hdmiInfo != nullptr)
+ {
+ auto currentMode = hdmiInfo.GetCurrentDisplayMode();
+ // On Xbox, 4K resolutions only are reported by HdmiDisplayInformation API
+ // so ScreenHeight & ScreenWidth are updated with info provided here
+ md.ScreenHeight = currentMode.ResolutionHeightInRawPixels();
+ md.ScreenWidth = currentMode.ResolutionWidthInRawPixels();
+ md.RefreshRate = currentMode.RefreshRate();
+ md.Bpp = currentMode.BitsPerPixel();
+ }
+ else
+ {
+ md.RefreshRate = 60.0;
+ md.Bpp = 24;
+ }
+ }
+ else
+ {
+ // note that refresh rate information is not available on Win10 UWP
+ md.RefreshRate = 60.0;
+ md.Bpp = 24;
+ }
+ md.Interlaced = false;
+
+ outputs.push_back(md);
+ });
+
+ if (dispatcher.HasThreadAccess())
+ handler();
+ else
+ Wait(dispatcher.RunAsync(CoreDispatcherPriority::High, handler));
+}
+
+void CWinSystemWin10::ShowOSMouse(bool show)
+{
+ if (!m_coreWindow)
+ return;
+
+ DispatchedHandler handler([this, show]()
+ {
+ CoreCursor cursor = nullptr;
+ if (show)
+ cursor = CoreCursor(CoreCursorType::Arrow, 1);
+ m_coreWindow.PointerCursor(cursor);
+ });
+
+ if (m_coreWindow.Dispatcher().HasThreadAccess())
+ handler();
+ else
+ m_coreWindow.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, handler);
+}
+
+bool CWinSystemWin10::Minimize()
+{
+ CLog::Log(LOGDEBUG, "{} is not implemented", __FUNCTION__);
+ return true;
+}
+bool CWinSystemWin10::Restore()
+{
+ CLog::Log(LOGDEBUG, "{} is not implemented", __FUNCTION__);
+ return true;
+}
+bool CWinSystemWin10::Hide()
+{
+ CLog::Log(LOGDEBUG, "{} is not implemented", __FUNCTION__);
+ return true;
+}
+bool CWinSystemWin10::Show(bool raise)
+{
+ CLog::Log(LOGDEBUG, "{} is not implemented", __FUNCTION__);
+ return true;
+}
+
+void CWinSystemWin10::Register(IDispResource *resource)
+{
+ std::unique_lock<CCriticalSection> lock(m_resourceSection);
+ m_resources.push_back(resource);
+}
+
+void CWinSystemWin10::Unregister(IDispResource* resource)
+{
+ std::unique_lock<CCriticalSection> lock(m_resourceSection);
+ std::vector<IDispResource*>::iterator i = find(m_resources.begin(), m_resources.end(), resource);
+ if (i != m_resources.end())
+ m_resources.erase(i);
+}
+
+void CWinSystemWin10::OnDisplayLost()
+{
+ CLog::Log(LOGDEBUG, "{} - notify display lost event", __FUNCTION__);
+
+ {
+ std::unique_lock<CCriticalSection> lock(m_resourceSection);
+ for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i)
+ (*i)->OnLostDisplay();
+ }
+}
+
+void CWinSystemWin10::OnDisplayReset()
+{
+ if (!m_delayDispReset)
+ {
+ CLog::Log(LOGDEBUG, "{} - notify display reset event", __FUNCTION__);
+ std::unique_lock<CCriticalSection> lock(m_resourceSection);
+ for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i)
+ (*i)->OnResetDisplay();
+ }
+}
+
+void CWinSystemWin10::OnDisplayBack()
+{
+ auto delay =
+ std::chrono::milliseconds(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
+ "videoscreen.delayrefreshchange") *
+ 100);
+ if (delay > 0ms)
+ {
+ m_delayDispReset = true;
+ m_dispResetTimer.Set(delay);
+ }
+ OnDisplayReset();
+}
+
+void CWinSystemWin10::ResolutionChanged()
+{
+ OnDisplayLost();
+ OnDisplayBack();
+}
+
+std::unique_ptr<CVideoSync> CWinSystemWin10::GetVideoSync(void *clock)
+{
+ std::unique_ptr<CVideoSync> pVSync(new CVideoSyncD3D(clock));
+ return pVSync;
+}
+
+std::string CWinSystemWin10::GetClipboardText()
+{
+ std::wstring unicode_text;
+
+ auto contentView = Clipboard::GetContent();
+ if (contentView.Contains(StandardDataFormats::Text()))
+ {
+ auto text = Wait(contentView.GetTextAsync());
+ unicode_text.append(text.c_str());
+ }
+
+ return KODI::PLATFORM::WINDOWS::FromW(unicode_text);
+}
+
+bool CWinSystemWin10::UseLimitedColor()
+{
+ return CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_VIDEOSCREEN_LIMITEDRANGE);
+}
+
+void CWinSystemWin10::NotifyAppFocusChange(bool bGaining)
+{
+ m_inFocus = bGaining;
+}
+
+void CWinSystemWin10::UpdateStates(bool fullScreen)
+{
+ m_fullscreenState = WINDOW_FULLSCREEN_STATE_FULLSCREEN_WINDOW; // currently only this allowed
+ m_windowState = WINDOW_WINDOW_STATE_WINDOWED; // currently only this allowed
+}
+
+WINDOW_STATE CWinSystemWin10::GetState(bool fullScreen) const
+{
+ return static_cast<WINDOW_STATE>(fullScreen ? m_fullscreenState : m_windowState);
+}
+
+bool CWinSystemWin10::MessagePump()
+{
+ return m_winEvents->MessagePump();
+}
+
+int CWinSystemWin10::GetGuiSdrPeakLuminance() const
+{
+ const auto settings = CServiceBroker::GetSettingsComponent()->GetSettings();
+
+ return settings->GetInt(CSettings::SETTING_VIDEOSCREEN_GUISDRPEAKLUMINANCE);
+}
+
+#pragma pack(pop)
diff --git a/xbmc/windowing/win10/WinSystemWin10.h b/xbmc/windowing/win10/WinSystemWin10.h
new file mode 100644
index 0000000..0f2b41e
--- /dev/null
+++ b/xbmc/windowing/win10/WinSystemWin10.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/DispResource.h"
+#include "threads/CriticalSection.h"
+#include "threads/SystemClock.h"
+#include "windowing/WinSystem.h"
+
+#include <vector>
+
+#pragma pack(push)
+#pragma pack(8)
+
+/* Controls the way the window appears and behaves. */
+enum WINDOW_STATE
+{
+ WINDOW_STATE_FULLSCREEN = 1, // Exclusive fullscreen
+ WINDOW_STATE_FULLSCREEN_WINDOW, // Non-exclusive fullscreen window
+ WINDOW_STATE_WINDOWED, //Movable window with border
+ WINDOW_STATE_BORDERLESS //Non-movable window with no border
+};
+
+static const char* window_state_names[] =
+{
+ "unknown",
+ "true fullscreen",
+ "windowed fullscreen",
+ "windowed",
+ "borderless"
+};
+
+/* WINDOW_STATE restricted to fullscreen modes. */
+enum WINDOW_FULLSCREEN_STATE
+{
+ WINDOW_FULLSCREEN_STATE_FULLSCREEN = WINDOW_STATE_FULLSCREEN,
+ WINDOW_FULLSCREEN_STATE_FULLSCREEN_WINDOW = WINDOW_STATE_FULLSCREEN_WINDOW
+};
+
+/* WINDOW_STATE restricted to windowed modes. */
+enum WINDOW_WINDOW_STATE
+{
+ WINDOW_WINDOW_STATE_WINDOWED = WINDOW_STATE_WINDOWED,
+ WINDOW_WINDOW_STATE_BORDERLESS = WINDOW_STATE_BORDERLESS
+};
+
+struct MONITOR_DETAILS
+{
+ // Windows desktop info
+ int ScreenWidth;
+ int ScreenHeight;
+ float RefreshRate;
+ int Bpp;
+ bool Interlaced;
+};
+
+class CWinSystemWin10 : public CWinSystemBase
+{
+public:
+ CWinSystemWin10();
+ virtual ~CWinSystemWin10();
+
+ // CWinSystemBase overrides
+ bool InitWindowSystem() override;
+ bool DestroyWindowSystem() override;
+ bool ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) override;
+ void FinishWindowResize(int newWidth, int newHeight) override;
+ void UpdateResolutions() override;
+ void NotifyAppFocusChange(bool bGaining) override;
+ void ShowOSMouse(bool show) override;
+ bool HasInertialGestures() override { return true; }//if win32 has touchscreen - it uses the win32 gesture api for inertial scrolling
+ bool Minimize() override;
+ bool Restore() override;
+ bool Hide() override;
+ bool Show(bool raise = true) override;
+ std::string GetClipboardText() override;
+ bool UseLimitedColor() override;
+
+ // videosync
+ std::unique_ptr<CVideoSync> GetVideoSync(void *clock) override;
+
+ bool WindowedMode() const { return m_state != WINDOW_STATE_FULLSCREEN; }
+ bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) override;
+
+ // CWinSystemWin10
+ bool IsAlteringWindow() const { return m_IsAlteringWindow; }
+ void SetAlteringWindow(bool altering) { m_IsAlteringWindow = altering; }
+ bool IsTogglingHDR() const { return false; }
+ void SetTogglingHDR(bool toggling) {}
+ virtual bool DPIChanged(WORD dpi, RECT windowRect) const;
+ bool IsMinimized() const { return m_bMinimized; }
+ void SetMinimized(bool minimized) { m_bMinimized = minimized; }
+ int GetGuiSdrPeakLuminance() const;
+
+ bool CanDoWindowed() override;
+
+ // winevents override
+ bool MessagePump() override;
+
+protected:
+ bool CreateNewWindow(const std::string& name, bool fullScreen, RESOLUTION_INFO& res) override = 0;
+ virtual void UpdateStates(bool fullScreen);
+ WINDOW_STATE GetState(bool fullScreen) const;
+ virtual void SetDeviceFullScreen(bool fullScreen, RESOLUTION_INFO& res) = 0;
+ virtual void ReleaseBackBuffer() = 0;
+ virtual void CreateBackBuffer() = 0;
+ virtual void ResizeDeviceBuffers() = 0;
+ virtual bool IsStereoEnabled() = 0;
+ virtual void AdjustWindow();
+
+ virtual void Register(IDispResource *resource);
+ virtual void Unregister(IDispResource *resource);
+
+ bool ChangeResolution(const RESOLUTION_INFO& res, bool forceChange = false);
+ const MONITOR_DETAILS* GetDefaultMonitor() const;
+ void RestoreDesktopResolution();
+ void GetConnectedDisplays(std::vector<MONITOR_DETAILS>& outputs);
+
+ /*!
+ \brief Adds a resolution to the list of resolutions if we don't already have it
+ \param res resolution to add.
+ */
+ static bool AddResolution(const RESOLUTION_INFO &res);
+
+ void OnDisplayLost();
+ void OnDisplayReset();
+ void OnDisplayBack();
+ void ResolutionChanged();
+
+ std::vector<MONITOR_DETAILS> m_displays;
+ bool m_ValidWindowedPosition;
+ bool m_IsAlteringWindow;
+
+ CCriticalSection m_resourceSection;
+ std::vector<IDispResource*> m_resources;
+ bool m_delayDispReset;
+ XbmcThreads::EndTime<> m_dispResetTimer;
+
+ WINDOW_STATE m_state; // the state of the window
+ WINDOW_FULLSCREEN_STATE m_fullscreenState; // the state of the window when in fullscreen
+ WINDOW_WINDOW_STATE m_windowState; // the state of the window when in windowed
+ bool m_inFocus;
+ bool m_bMinimized;
+ bool m_bFirstResChange = true;
+
+ winrt::Windows::UI::Core::CoreWindow m_coreWindow = nullptr;
+};
+
+#pragma pack(pop)
+
diff --git a/xbmc/windowing/win10/WinSystemWin10DX.cpp b/xbmc/windowing/win10/WinSystemWin10DX.cpp
new file mode 100644
index 0000000..c3d2fca
--- /dev/null
+++ b/xbmc/windowing/win10/WinSystemWin10DX.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "WinSystemWin10DX.h"
+
+#include "input/touch/generic/GenericTouchActionHandler.h"
+#include "input/touch/generic/GenericTouchInputHandler.h"
+#include "rendering/dx/DirectXHelper.h"
+#include "utils/XTimeUtils.h"
+#include "utils/log.h"
+#include "windowing/WindowSystemFactory.h"
+
+#include "platform/win32/WIN32Util.h"
+
+using namespace std::chrono_literals;
+
+void CWinSystemWin10DX::Register()
+{
+ KODI::WINDOWING::CWindowSystemFactory::RegisterWindowSystem(CreateWinSystem);
+}
+
+std::unique_ptr<CWinSystemBase> CWinSystemWin10DX::CreateWinSystem()
+{
+ return std::make_unique<CWinSystemWin10DX>();
+}
+
+CWinSystemWin10DX::CWinSystemWin10DX() : CRenderSystemDX()
+{
+}
+
+CWinSystemWin10DX::~CWinSystemWin10DX()
+{
+}
+
+void CWinSystemWin10DX::PresentRenderImpl(bool rendered)
+{
+ if (rendered)
+ m_deviceResources->Present();
+
+ if (m_delayDispReset && m_dispResetTimer.IsTimePast())
+ {
+ m_delayDispReset = false;
+ OnDisplayReset();
+ }
+
+ if (!rendered)
+ KODI::TIME::Sleep(40ms);
+}
+
+bool CWinSystemWin10DX::CreateNewWindow(const std::string& name, bool fullScreen, RESOLUTION_INFO& res)
+{
+ const MONITOR_DETAILS* monitor = GetDefaultMonitor();
+ if (!monitor)
+ return false;
+
+ m_deviceResources = DX::DeviceResources::Get();
+ m_deviceResources->SetWindow(m_coreWindow);
+
+ if (CWinSystemWin10::CreateNewWindow(name, fullScreen, res) && m_deviceResources->HasValidDevice())
+ {
+ CGenericTouchInputHandler::GetInstance().RegisterHandler(&CGenericTouchActionHandler::GetInstance());
+ CGenericTouchInputHandler::GetInstance().SetScreenDPI(m_deviceResources->GetDpi());
+ return true;
+ }
+ return false;
+}
+
+bool CWinSystemWin10DX::DestroyRenderSystem()
+{
+ CRenderSystemDX::DestroyRenderSystem();
+
+ m_deviceResources->Release();
+ m_deviceResources.reset();
+ return true;
+}
+
+void CWinSystemWin10DX::ShowSplash(const std::string & message)
+{
+ CRenderSystemBase::ShowSplash(message);
+
+ // this will prevent killing the app by watchdog timeout during loading
+ if (m_coreWindow != nullptr)
+ m_coreWindow.Dispatcher().ProcessEvents(winrt::Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent);
+}
+
+void CWinSystemWin10DX::SetDeviceFullScreen(bool fullScreen, RESOLUTION_INFO& res)
+{
+ m_deviceResources->SetFullScreen(fullScreen, res);
+}
+
+bool CWinSystemWin10DX::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
+{
+ CWinSystemWin10::ResizeWindow(newWidth, newHeight, newLeft, newTop);
+ CRenderSystemDX::OnResize();
+
+ return true;
+}
+
+void CWinSystemWin10DX::OnMove(int x, int y)
+{
+ m_deviceResources->SetWindowPos(m_coreWindow.Bounds());
+}
+
+bool CWinSystemWin10DX::DPIChanged(WORD dpi, RECT windowRect) const
+{
+ m_deviceResources->SetDpi(dpi);
+ if (!IsAlteringWindow())
+ return CWinSystemWin10::DPIChanged(dpi, windowRect);
+
+ return true;
+}
+
+void CWinSystemWin10DX::ReleaseBackBuffer()
+{
+ m_deviceResources->ReleaseBackBuffer();
+}
+
+void CWinSystemWin10DX::CreateBackBuffer()
+{
+ m_deviceResources->CreateBackBuffer();
+}
+
+void CWinSystemWin10DX::ResizeDeviceBuffers()
+{
+ m_deviceResources->ResizeBuffers();
+}
+
+bool CWinSystemWin10DX::IsStereoEnabled()
+{
+ return m_deviceResources->IsStereoEnabled();
+}
+
+void CWinSystemWin10DX::OnResize(int width, int height)
+{
+ if (!m_deviceResources)
+ return;
+
+ if (!m_IsAlteringWindow)
+ ReleaseBackBuffer();
+
+ m_deviceResources->SetLogicalSize(width, height);
+
+ if (!m_IsAlteringWindow)
+ CreateBackBuffer();
+}
+
+bool CWinSystemWin10DX::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
+{
+ bool const result = CWinSystemWin10::SetFullScreen(fullScreen, res, blankOtherDisplays);
+ CRenderSystemDX::OnResize();
+ return result;
+}
+
+void CWinSystemWin10DX::UninitHooks()
+{
+}
+
+void CWinSystemWin10DX::InitHooks(IDXGIOutput* pOutput)
+{
+}
+
+bool CWinSystemWin10DX::IsHDRDisplay()
+{
+ return false; // use tone mapping by default on Xbox
+}
+
+HDR_STATUS CWinSystemWin10DX::GetOSHDRStatus()
+{
+ return CWIN32Util::GetWindowsHDRStatus();
+}
+
+HDR_STATUS CWinSystemWin10DX::ToggleHDR()
+{
+ return m_deviceResources->ToggleHDR();
+}
+
+bool CWinSystemWin10DX::IsHDROutput() const
+{
+ return m_deviceResources->IsHDROutput();
+}
+
+bool CWinSystemWin10DX::IsTransferPQ() const
+{
+ return m_deviceResources->IsTransferPQ();
+}
+
+void CWinSystemWin10DX::SetHdrMetaData(DXGI_HDR_METADATA_HDR10& hdr10) const
+{
+ m_deviceResources->SetHdrMetaData(hdr10);
+}
+
+void CWinSystemWin10DX::SetHdrColorSpace(const DXGI_COLOR_SPACE_TYPE colorSpace) const
+{
+ m_deviceResources->SetHdrColorSpace(colorSpace);
+}
+
+DEBUG_INFO_RENDER CWinSystemWin10DX::GetDebugInfo()
+{
+ return m_deviceResources->GetDebugInfo();
+}
diff --git a/xbmc/windowing/win10/WinSystemWin10DX.h b/xbmc/windowing/win10/WinSystemWin10DX.h
new file mode 100644
index 0000000..84ad660
--- /dev/null
+++ b/xbmc/windowing/win10/WinSystemWin10DX.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "HDRStatus.h"
+#include "WinSystemWin10.h"
+#include "rendering/dx/RenderSystemDX.h"
+
+class CWinSystemWin10DX : public CWinSystemWin10, public CRenderSystemDX
+{
+public:
+ CWinSystemWin10DX();
+ ~CWinSystemWin10DX();
+
+ static void Register();
+ static std::unique_ptr<CWinSystemBase> CreateWinSystem();
+
+ // Implementation of CWinSystemBase via CWinSystemWin10
+ CRenderSystemBase *GetRenderSystem() override { return this; }
+ bool CreateNewWindow(const std::string& name, bool fullScreen, RESOLUTION_INFO& res) override;
+ bool ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) override;
+ bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) override;
+ void PresentRenderImpl(bool rendered) override;
+ bool DPIChanged(WORD dpi, RECT windowRect) const override;
+ bool DestroyRenderSystem() override;
+ void* GetHWContext() override { return m_deviceResources->GetD3DContext(); }
+
+ void UninitHooks();
+ void InitHooks(IDXGIOutput* pOutput);
+
+ void OnMove(int x, int y) override;
+ void OnResize(int width, int height);
+ winrt::Windows::Foundation::Size GetOutputSize() const { return m_deviceResources->GetOutputSize(); }
+ void TrimDevice() const { m_deviceResources->Trim(); }
+
+ /*!
+ \brief Register as a dependent of the DirectX Render System
+ Resources should call this on construction if they're dependent on the Render System
+ for survival. Any resources that registers will get callbacks on loss and reset of
+ device. In addition, callbacks for destruction and creation of the device are also called,
+ where any resources dependent on the DirectX device should be destroyed and recreated.
+ \sa Unregister, ID3DResource
+ */
+ void Register(ID3DResource *resource) const
+ {
+ m_deviceResources->Register(resource);
+ };
+ /*!
+ \brief Unregister as a dependent of the DirectX Render System
+ Resources should call this on destruction if they're a dependent on the Render System
+ \sa Register, ID3DResource
+ */
+ void Unregister(ID3DResource *resource) const
+ {
+ m_deviceResources->Unregister(resource);
+ };
+
+ void Register(IDispResource* resource) override { CWinSystemWin10::Register(resource); }
+ void Unregister(IDispResource* resource) override { CWinSystemWin10::Unregister(resource); }
+
+ void ShowSplash(const std::string& message) override;
+
+ // HDR OS/display override
+ bool IsHDRDisplay() override;
+ HDR_STATUS ToggleHDR() override;
+ HDR_STATUS GetOSHDRStatus() override;
+
+ // HDR support
+ bool IsHDROutput() const;
+ bool IsTransferPQ() const;
+ void SetHdrMetaData(DXGI_HDR_METADATA_HDR10& hdr10) const;
+ void SetHdrColorSpace(const DXGI_COLOR_SPACE_TYPE colorSpace) const;
+
+ // Get debug info from swapchain
+ DEBUG_INFO_RENDER GetDebugInfo() override;
+
+protected:
+ void SetDeviceFullScreen(bool fullScreen, RESOLUTION_INFO& res) override;
+ void ReleaseBackBuffer() override;
+ void CreateBackBuffer() override;
+ void ResizeDeviceBuffers() override;
+ bool IsStereoEnabled() override;
+};
+