Files
Xenia-Canary/src/xenia/ui/windowed_app_context_win.h
2022-02-13 23:07:27 +03:00

114 lines
4.5 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2022 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_WINDOWED_APP_CONTEXT_WIN_H_
#define XENIA_UI_WINDOWED_APP_CONTEXT_WIN_H_
#include <memory>
#include "xenia/base/platform_win.h"
#include "xenia/ui/windowed_app_context.h"
// For per-monitor DPI awareness v1.
#include <ShellScalingApi.h>
namespace xe {
namespace ui {
class Win32WindowedAppContext final : public WindowedAppContext {
public:
// clang-format off
struct PerMonitorDpiV1Api {
HRESULT (STDAPICALLTYPE* get_dpi_for_monitor)(
HMONITOR hmonitor, MONITOR_DPI_TYPE dpi_type, UINT* dpi_x, UINT* dpi_y);
};
struct PerMonitorDpiV2Api {
// Important note: Even though per-monitor DPI awareness version 2
// inherently has automatic non-client area DPI scaling, PMv2 was added in
// Windows 10 1703. However, these functions were added earlier, in 1607.
// While we haven't tested the actual behavior on 1607 and this is just a
// guess, still, before using AdjustWindowRectExForDpi for the window DPI,
// make sure that EnableNonClientDpiScaling is called for the window in its
// WM_NCCREATE handler to enable automatic non-client DPI scaling on PMv1 on
// 1607, so AdjustWindowRectExForDpi (which doesn't have a window argument
// so it can't know whether automatic scaling is enabled for it) will likely
// return values that reflect the actual size of the non-client area of the
// window (otherwise, for instance, "un-adjusting" the actual window
// rectangle using AdjustWindowRectExForDpi may result in a negative client
// area size if the DPI passed to it is larger than the DPI actually used
// for the non-client area).
BOOL (WINAPI* adjust_window_rect_ex_for_dpi)(
LPRECT rect, DWORD style, BOOL menu, DWORD ex_style, UINT dpi);
BOOL (WINAPI* enable_non_client_dpi_scaling)(HWND hwnd);
UINT (WINAPI* get_dpi_for_system)();
UINT (WINAPI* get_dpi_for_window)(HWND hwnd);
};
// clang-format on
// Must call Initialize and check its result after creating to be able to
// perform pending function calls.
explicit Win32WindowedAppContext(HINSTANCE hinstance, int show_cmd)
: hinstance_(hinstance), show_cmd_(show_cmd) {}
~Win32WindowedAppContext();
bool Initialize();
HINSTANCE hinstance() const { return hinstance_; }
int show_cmd() const { return show_cmd_; }
void NotifyUILoopOfPendingFunctions() override;
void PlatformQuitFromUIThread() override;
int RunMainMessageLoop();
// Per-monitor DPI awareness version 2 is expected to be enabled via the
// manifest, as that's the recommended way, which also doesn't require calling
// SetProcessDpiAwareness before doing anything that may depend on DPI
// awareness (so it's safe to use any Windows APIs before what would be
// supposed to initialize it).
// Windows 8.1 per-monitor DPI awareness version 1.
const PerMonitorDpiV1Api* per_monitor_dpi_v1_api() const {
return per_monitor_dpi_v1_api_available_ ? &per_monitor_dpi_v1_api_
: nullptr;
}
// Windows 10 1607 per-monitor DPI awareness API, also heavily used for
// per-monitor DPI awareness version 2 functionality added in Windows 10 1703.
const PerMonitorDpiV2Api* per_monitor_dpi_v2_api() const {
return per_monitor_dpi_v2_api_available_ ? &per_monitor_dpi_v2_api_
: nullptr;
}
private:
enum : UINT {
kPendingFunctionsWindowClassMessageExecute = WM_USER,
};
static LRESULT CALLBACK PendingFunctionsWndProc(HWND hwnd, UINT message,
WPARAM wparam, LPARAM lparam);
HINSTANCE hinstance_;
int show_cmd_;
HMODULE shcore_module_ = nullptr;
HMODULE user32_module_ = nullptr;
PerMonitorDpiV1Api per_monitor_dpi_v1_api_ = {};
PerMonitorDpiV2Api per_monitor_dpi_v2_api_ = {};
bool per_monitor_dpi_v1_api_available_ = false;
bool per_monitor_dpi_v2_api_available_ = false;
static bool pending_functions_window_class_registered_;
HWND pending_functions_hwnd_ = nullptr;
};
} // namespace ui
} // namespace xe
#endif // XENIA_UI_WINDOWED_APP_CONTEXT_WIN_H_