<div dir="ltr">Thanks for the review, comments are inline.<br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Aug 2, 2016 at 4:31 PM, Frediano Ziglio <span dir="ltr"><<a href="mailto:fziglio@redhat.com" target="_blank">fziglio@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div class=""><div class="h5">><br>
> The Connecting and Configuring Displays (CCD) Win32 APIs<br>
> provide more control over the desktop display setup. The CCD APIs<br>
> move away from using Windows Graphics Device Interface (GDI)<br>
> concepts like view name and toward Windows Display Driver Model<br>
> (WDDM) concepts like adapter, source, and target identifiers.<br>
> More info on the CCD API can be found here:<br>
> <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff539590(v=vs.85).aspx" rel="noreferrer" target="_blank">https://msdn.microsoft.com/en-us/library/windows/hardware/ff539590(v=vs.85).aspx</a><br>
><br>
> This patch introduces partial functionality from the CCD API<br>
> needed by vdagent. It is needed by vdagent in order to support<br>
> multiple monitors and arbitrary resolution on Windows 10.<br>
><br>
> Tested with both Windows 10 and Windows 7.<br>
><br>
> Based on a patch by Sandy Stutsman <<a href="mailto:sstutsma@redhat.com">sstutsma@redhat.com</a>><br>
><br>
> Signed-off-by: Dmitry Fleytman <<a href="mailto:dfleytma@redhat.com">dfleytma@redhat.com</a>><br>
> Signed-off-by: Sameeh Jubran <<a href="mailto:sameeh@daynix.com">sameeh@daynix.com</a>><br>
> ---<br>
> Makefile.am | 2 +<br>
> vdagent/desktop_layout.cpp | 150 ++----<br>
> vdagent/desktop_layout.h | 9 +-<br>
> vdagent/display_configuration.cpp | 1071<br>
> +++++++++++++++++++++++++++++++++++++<br>
> vdagent/display_configuration.h | 191 +++++++<br>
> 5 files changed, 1301 insertions(+), 122 deletions(-)<br>
> create mode 100755 vdagent/display_configuration.cpp<br>
> create mode 100755 vdagent/display_configuration.h<br>
><br>
> diff --git a/Makefile.am b/Makefile.am<br>
> index c3fc6bf..84507e8 100644<br>
> --- a/Makefile.am<br>
> +++ b/Makefile.am<br>
> @@ -31,6 +31,8 @@ vdagent_SOURCES = \<br>
> common/vdcommon.h \<br>
> common/vdlog.cpp \<br>
> common/vdlog.h \<br>
> + vdagent/display_configuration.cpp \<br>
> + vdagent/display_configuration.h \<br>
> vdagent/desktop_layout.cpp \<br>
> vdagent/desktop_layout.h \<br>
> vdagent/display_setting.cpp \<br>
> diff --git a/vdagent/desktop_layout.cpp b/vdagent/desktop_layout.cpp<br>
> index a7666ca..e59a1a4 100644<br>
> --- a/vdagent/desktop_layout.cpp<br>
> +++ b/vdagent/desktop_layout.cpp<br>
> @@ -18,6 +18,7 @@<br>
> #include <spice/qxl_windows.h><br>
> #include <spice/qxl_dev.h><br>
> #include "desktop_layout.h"<br>
> +#include "display_configuration.h"<br>
> #include "vdlog.h"<br>
><br>
> #ifdef __MINGW32__<br>
> @@ -35,15 +36,19 @@ void DisplayMode::set_res(DWORD width, DWORD height,<br>
> DWORD depth)<br>
> DesktopLayout::DesktopLayout()<br>
> : _total_width (0)<br>
> , _total_height (0)<br>
> - , _send_monitors_position(false)<br>
> + , _display_config (NULL)<br>
> {<br>
> MUTEX_INIT(_mutex);<br>
> + _display_config = DisplayConfig::create_config();<br>
> get_displays();<br>
> }<br>
><br>
> DesktopLayout::~DesktopLayout()<br>
> {<br>
> clean_displays();<br>
> + if (_display_config) {<br>
> + delete _display_config;<br>
> + }<br>
<br>
</div></div>just delete _display_config, the if is redundant.<br>
<div><div class="h5"><br>
> }<br>
><br>
> void DesktopLayout::get_displays()<br>
> @@ -59,6 +64,7 @@ void DesktopLayout::get_displays()<br>
> unlock();<br>
> return;<br>
> }<br>
> + _display_config->update_config_path();<br>
> clean_displays();<br>
> ZeroMemory(&dev_info, sizeof(dev_info));<br>
> dev_info.cb = sizeof(dev_info);<br>
> @@ -82,12 +88,13 @@ void DesktopLayout::get_displays()<br>
> _displays[i] = NULL;<br>
> }<br>
> }<br>
> - attached = !!(dev_info.StateFlags &<br>
> DISPLAY_DEVICE_ATTACHED_TO_DESKTOP);<br>
> + attached = _display_config->is_attached(&dev_info);<br>
> +<br>
> EnumDisplaySettings(dev_info.DeviceName, ENUM_CURRENT_SETTINGS,<br>
> &mode);<br>
> _displays[display_id] = new DisplayMode(mode.dmPosition.x,<br>
> mode.dmPosition.y,<br>
> mode.dmPelsWidth,<br>
> mode.dmPelsHeight,<br>
> mode.dmBitsPerPel,<br>
> attached);<br>
> - update_monitor_config(dev_info.DeviceName, _displays[display_id]);<br>
> + _display_config->update_monitor_config(dev_info.DeviceName,<br>
> _displays[display_id], &mode);<br>
> }<br>
> normalize_displays_pos();<br>
> unlock();<br>
> @@ -121,6 +128,7 @@ void DesktopLayout::set_displays()<br>
> unlock();<br>
> return;<br>
> }<br>
> + _display_config->update_config_path();<br>
> ZeroMemory(&dev_info, sizeof(dev_info));<br>
> dev_info.cb = sizeof(dev_info);<br>
> ZeroMemory(&dev_mode, sizeof(dev_mode));<br>
> @@ -146,28 +154,32 @@ void DesktopLayout::set_displays()<br>
> break;<br>
> }<br>
> DisplayMode * mode(_<a href="http://displays.at" rel="noreferrer" target="_blank">displays.at</a>(display_id));<br>
> - if (!init_dev_mode(dev_info.DeviceName, &dev_mode, mode, normal_x,<br>
> normal_y, true)) {<br>
> + if (!init_dev_mode(dev_info.DeviceName, &dev_mode, mode)) {<br>
> vd_printf("No suitable mode found for display %S",<br>
> dev_info.DeviceName);<br>
> break;<br>
> }<br>
> vd_printf("Set display mode %lux%lu", dev_mode.dmPelsWidth,<br>
> dev_mode.dmPelsHeight);<br>
> - LONG ret = ChangeDisplaySettingsEx(dev_info.DeviceName, &dev_mode,<br>
> NULL,<br>
> - CDS_UPDATEREGISTRY | CDS_NORESET,<br>
> NULL);<br>
> - if (ret == DISP_CHANGE_SUCCESSFUL) {<br>
> + if (_display_config->update_dev_mode_position(dev_info.DeviceName,<br>
> &dev_mode,<br>
> + mode->_pos_x -<br>
> normal_x,<br>
> + mode->_pos_y -<br>
> normal_y)) {<br>
> dev_sets++;<br>
> - update_monitor_config(dev_info.DeviceName, mode);<br>
> + _display_config->update_monitor_config(dev_info.DeviceName,<br>
> mode, &dev_mode);<br>
> }<br>
> if (!is_qxl) {<br>
> display_id++;<br>
> }<br>
> }<br>
> if (dev_sets) {<br>
> - ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);<br>
> + _display_config->update_display_settings();<br>
> normalize_displays_pos();<br>
> }<br>
> unlock();<br>
> }<br>
><br>
> +void DesktopLayout::set_position_configurable(bool flag) {<br>
> + _display_config->set_monitors_config(flag);<br>
> +}<br>
> +<br>
> // Normalize all display positions to non-negative coordinates and update<br>
> total width and height of<br>
> // the virtual desktop. Caller is responsible to lock() & unlock().<br>
> void DesktopLayout::normalize_displays_pos()<br>
> @@ -265,125 +277,29 @@ bool DesktopLayout::get_qxl_device_id(WCHAR*<br>
> device_key, DWORD* device_id)<br>
> return key_found;<br>
> }<br>
><br>
> -bool DesktopLayout::init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode,<br>
> DisplayMode* mode,<br>
> - LONG normal_x, LONG normal_y, bool<br>
> set_pos)<br>
> +bool DesktopLayout::init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode,<br>
> DisplayMode* mode)<br>
> {<br>
> - DWORD closest_diff = -1;<br>
> - DWORD best = -1;<br>
> - QXLEscapeSetCustomDisplay custom;<br>
> - HDC hdc = NULL;<br>
> - LONG ret;<br>
> -<br>
> ZeroMemory(dev_mode, sizeof(DEVMODE));<br>
> dev_mode->dmSize = sizeof(DEVMODE);<br>
> - if (!mode || !mode->_attached) {<br>
> - //Detach monitor<br>
> - dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;<br>
> - return true;<br>
> - }<br>
> -<br>
> - hdc = CreateDC(dev_name, NULL, NULL, NULL);<br>
> - if (!hdc) {<br>
> - // for some reason, windows want those 3 flags to enable monitor<br>
> - dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;<br>
> - dev_mode->dmPelsWidth = mode->_width;<br>
> - dev_mode->dmPelsHeight = mode->_height;<br>
> - ret = ChangeDisplaySettingsEx(dev_name, dev_mode, NULL,<br>
> CDS_UPDATEREGISTRY, NULL);<br>
> - if (ret == DISP_CHANGE_BADMODE) {<br>
> - // custom resolution might not be set yet, use known resolution<br>
> - // FIXME: this causes client temporary resize... a<br>
> - // solution would involve passing custom resolution before<br>
> - // driver initialization, perhaps through registry<br>
> - dev_mode->dmPelsWidth = 640;<br>
> - dev_mode->dmPelsHeight = 480;<br>
> - ret = ChangeDisplaySettingsEx(dev_name, dev_mode, NULL,<br>
> CDS_UPDATEREGISTRY, NULL);<br>
> - }<br>
> -<br>
> - vd_printf("attach %ld", ret);<br>
> - hdc = CreateDC(dev_name, NULL, NULL, NULL);<br>
> - }<br>
><br>
> - if (!hdc) {<br>
> - vd_printf("failed to create DC");<br>
> - return false;<br>
> - } else {<br>
> - // Update custom resolution<br>
> - custom.xres = mode->_width;<br>
> - custom.yres = mode->_height;<br>
> - custom.bpp = mode->_depth;<br>
> -<br>
> - int err = ExtEscape(hdc, QXL_ESCAPE_SET_CUSTOM_DISPLAY,<br>
> - sizeof(QXLEscapeSetCustomDisplay),<br>
> (LPCSTR)&custom, 0, NULL);<br>
> - if (err <= 0) {<br>
> - vd_printf("can't set custom display, perhaps an old driver");<br>
> - }<br>
> - DeleteDC(hdc);<br>
> + //Update monitor state<br>
> + MONITOR_STATE monitor_state = (!mode || !mode->_attached)?<br>
> MONITOR_DETACHED : MONITOR_ATTACHED;<br>
> + _display_config->set_monitor_state(dev_name, dev_mode, monitor_state);<br>
> + if (monitor_state == MONITOR_DETACHED) {<br>
> + return true;<br>
> }<br>
><br>
> - // force refresh mode table<br>
> - DEVMODE tempDevMode;<br>
> - ZeroMemory(&tempDevMode, sizeof (tempDevMode));<br>
> - tempDevMode.dmSize = sizeof(DEVMODE);<br>
> - EnumDisplaySettings(dev_name, 0xffffff, &tempDevMode);<br>
> -<br>
> - //Find the closest size which will fit within the monitor<br>
> - for (DWORD i = 0; EnumDisplaySettings(dev_name, i, dev_mode); i++) {<br>
> - if (dev_mode->dmPelsWidth > mode->_width ||<br>
> - dev_mode->dmPelsHeight > mode->_height ||<br>
> - dev_mode->dmBitsPerPel != mode->_depth) {<br>
> - continue;<br>
> - }<br>
> - DWORD wdiff = mode->_width - dev_mode->dmPelsWidth;<br>
> - DWORD hdiff = mode->_height - dev_mode->dmPelsHeight;<br>
> - DWORD diff = wdiff * wdiff + hdiff * hdiff;<br>
> - if (diff < closest_diff) {<br>
> - closest_diff = diff;<br>
> - best = i;<br>
> - }<br>
> - }<br>
> - if (best == (DWORD)-1 || !EnumDisplaySettings(dev_name, best, dev_mode))<br>
> {<br>
> + // Update custom resolution<br>
> + dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;<br>
> + dev_mode->dmPelsWidth = mode->_width;<br>
> + dev_mode->dmPelsHeight = mode->_height;<br>
> + dev_mode->dmBitsPerPel = mode->_depth;<br>
> + if (!_display_config->custom_display_escape(dev_name, dev_mode))<br>
> return false;<br>
> - }<br>
> - dev_mode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;<br>
> - if (set_pos) {<br>
> - //Convert the position so that the primary is always at (0,0)<br>
> - dev_mode->dmPosition.x = mode->_pos_x - normal_x;<br>
> - dev_mode->dmPosition.y = mode->_pos_y - normal_y;<br>
> - dev_mode->dmFields |= DM_POSITION;<br>
> - }<br>
><br>
> // update current DisplayMode (so mouse scaling works properly)<br>
> mode->_width = dev_mode->dmPelsWidth;<br>
> mode->_height = dev_mode->dmPelsHeight;<br>
> -<br>
> return true;<br>
> -}<br>
> -<br>
> -bool DesktopLayout::update_monitor_config(LPCTSTR dev_name, DisplayMode*<br>
> mode)<br>
> -{<br>
> - QXLHead monitor_config;<br>
> -<br>
> - if (!mode || !mode->get_attached())<br>
> - return false;<br>
> -<br>
> - //Don't configure monitors unless the client supports it<br>
> - if(!_send_monitors_position) return FALSE;<br>
> -<br>
> - HDC hdc = CreateDC(dev_name, NULL, NULL, NULL);<br>
> -<br>
> - memset(&monitor_config, 0, sizeof(monitor_config));<br>
> - monitor_config.x = mode->_pos_x;<br>
> - monitor_config.y = mode->_pos_y;<br>
> - monitor_config.width = mode->_width;<br>
> - monitor_config.height = mode->_height;<br>
> -<br>
> - int err = ExtEscape(hdc, QXL_ESCAPE_MONITOR_CONFIG,<br>
> - sizeof(QXLHead), (LPCSTR) &monitor_config, 0, NULL);<br>
> -<br>
> - if (err < 0){<br>
> - vd_printf("can't update monitor config, may have an older driver");<br>
> - }<br>
><br>
> - DeleteDC(hdc);<br>
> - return (err >= 0);<br>
> }<br>
> diff --git a/vdagent/desktop_layout.h b/vdagent/desktop_layout.h<br>
> index ece3946..fd6af76 100644<br>
> --- a/vdagent/desktop_layout.h<br>
> +++ b/vdagent/desktop_layout.h<br>
> @@ -60,6 +60,7 @@ private:<br>
> };<br>
><br>
> typedef std::vector<DisplayMode*> Displays;<br>
> +class DisplayConfig;<br>
><br>
> class DesktopLayout {<br>
> public:<br>
> @@ -73,23 +74,21 @@ public:<br>
> size_t get_display_count() { return _displays.size();}<br>
> DWORD get_total_width() { return _total_width;}<br>
> DWORD get_total_height() { return _total_height;}<br>
> - void set_position_configurable(bool flag) { _send_monitors_position =<br>
> flag; }<br>
> + void set_position_configurable(bool flag);<br>
> private:<br>
> void clean_displays();<br>
> void normalize_displays_pos();<br>
> DisplayMode * get_primary_display();<br>
> - bool update_monitor_config(LPCTSTR dev_name, DisplayMode* mode);<br>
> + bool init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode, DisplayMode*<br>
> mode);<br>
> static bool consistent_displays();<br>
> static bool is_attached(LPCTSTR dev_name);<br>
> static bool get_qxl_device_id(WCHAR* device_key, DWORD* device_id);<br>
> - static bool init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode,<br>
> DisplayMode* mode,<br>
> - LONG normal_x, LONG normal_y, bool set_pos);<br>
> private:<br>
> mutex_t _mutex;<br>
> Displays _displays;<br>
> DWORD _total_width;<br>
> DWORD _total_height;<br>
> - bool _send_monitors_position;<br>
> + DisplayConfig* _display_config;<br>
> };<br>
><br>
> #endif<br>
> diff --git a/vdagent/display_configuration.cpp<br>
> b/vdagent/display_configuration.cpp<br>
> new file mode 100755<br>
> index 0000000..563f619<br>
> --- /dev/null<br>
> +++ b/vdagent/display_configuration.cpp<br>
> @@ -0,0 +1,1071 @@<br>
> +/*<br>
> +Copyright (C) 2015 Red Hat, Inc.<br>
> +<br>
> +This program is free software; you can redistribute it and/or<br>
> +modify it under the terms of the GNU General Public License as<br>
> +published by the Free Software Foundation; either version 2 of<br>
> +the License, or (at your option) any later version.<br>
> +<br>
> +This program is distributed in the hope that it will be useful,<br>
> +but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
> +GNU General Public License for more details.<br>
> +<br>
> +You should have received a copy of the GNU General Public License<br>
> +along with this program. If not, see <<a href="http://www.gnu.org/licenses/" rel="noreferrer" target="_blank">http://www.gnu.org/licenses/</a>>.<br>
> +*/<br>
> +<br>
> +#include "display_configuration.h"<br>
> +#include <winternl.h><br>
> +<br>
> +//<br>
> +// Definitions used by QueryDisplayConfig.<br>
> +//<br>
> +<br>
> +#define QDC_ALL_PATHS 0x00000001<br>
> +<br>
> +//<br>
> +// Definitions used by SetDisplayConfig.<br>
> +//<br>
> +<br>
> +#define SDC_USE_SUPPLIED_DISPLAY_CONFIG 0x00000020<br>
> +#define SDC_APPLY 0x00000080<br>
> +#define SDC_FORCE_MODE_ENUMERATION 0x00001000<br>
> +<br>
> +#define DISPLAYCONFIG_PATH_ACTIVE 0x00000001<br>
> +#define DISPLAYCONFIG_PATH_MODE_IDX_INVALID 0xffffffff<br>
> +<br>
> +enum DISPLAYCONFIG_DEVICE_INFO_TYPE {<br>
> + DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1<br>
> +};<br>
> +<br>
> +enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY {};<br>
> +<br>
> +enum DISPLAYCONFIG_ROTATION {};<br>
> +<br>
> +enum DISPLAYCONFIG_SCANLINE_ORDERING {};<br>
> +<br>
> +enum DISPLAYCONFIG_SCALING {};<br>
> +<br>
> +enum DISPLAYCONFIG_PIXELFORMAT {};<br>
> +<br>
> +enum DISPLAYCONFIG_MODE_INFO_TYPE {};<br>
> +<br>
> +struct DISPLAYCONFIG_DEVICE_INFO_HEADER {<br>
> + DISPLAYCONFIG_DEVICE_INFO_TYPE type;<br>
> + UINT32 size;<br>
> + LUID adapterId;<br>
> + UINT32 id;<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_SOURCE_DEVICE_NAME {<br>
> + DISPLAYCONFIG_DEVICE_INFO_HEADER header;<br>
> + WCHAR<br>
> viewGdiDeviceName[CCHDEVICENAME];<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO {<br>
> + POINTL PathSourceSize;<br>
> + RECTL DesktopImageRegion;<br>
> + RECTL DesktopImageClip;<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_RATIONAL {<br>
> + UINT32 Numerator;<br>
> + UINT32 Denominator;<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_2DREGION {<br>
> + UINT32 cx;<br>
> + UINT32 cy;<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO {<br>
> + UINT64 pixelRate;<br>
> + DISPLAYCONFIG_RATIONAL hSyncFreq;<br>
> + DISPLAYCONFIG_RATIONAL vSyncFreq;<br>
> + DISPLAYCONFIG_2DREGION activeSize;<br>
> + DISPLAYCONFIG_2DREGION totalSize;<br>
> +<br>
> + union {<br>
> + struct {<br>
> + UINT32 videoStandard : 16;<br>
> + UINT32 vSyncFreqDivider : 6;<br>
> + UINT32 reserved : 10;<br>
> + } AdditionalSignalInfo;<br>
> + UINT32 videoStandard;<br>
> + } DUMMYUNIONNAME;<br>
> + DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_TARGET_MODE {<br>
> + DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_SOURCE_MODE {<br>
> + UINT32 width;<br>
> + UINT32 height;<br>
> + DISPLAYCONFIG_PIXELFORMAT pixelFormat;<br>
> + POINTL position;<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_MODE_INFO {<br>
> + DISPLAYCONFIG_MODE_INFO_TYPE infoType;<br>
> + UINT32 id;<br>
> + LUID adapterId;<br>
> + union {<br>
> + DISPLAYCONFIG_TARGET_MODE targetMode;<br>
> + DISPLAYCONFIG_SOURCE_MODE sourceMode;<br>
> + DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo;<br>
> + } DUMMYUNIONNAME;<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_PATH_SOURCE_INFO {<br>
> + LUID adapterId;<br>
> + UINT32 id;<br>
> + union {<br>
> + UINT32 modeInfoIdx;<br>
> + struct {<br>
> + UINT32 cloneGroupId : 16;<br>
> + UINT32 sourceModeInfoIdx : 16;<br>
> + } DUMMYSTRUCTNAME;<br>
> + } DUMMYUNIONNAME;<br>
> +<br>
> + UINT32 statusFlags;<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_PATH_TARGET_INFO {<br>
> + LUID adapterId;<br>
> + UINT32 id;<br>
> + union {<br>
> + UINT32 modeInfoIdx;<br>
> + struct {<br>
> + UINT32 desktopModeInfoIdx : 16;<br>
> + UINT32 targetModeInfoIdx : 16;<br>
> + } DUMMYSTRUCTNAME;<br>
> + } DUMMYUNIONNAME;<br>
> + DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;<br>
> + DISPLAYCONFIG_ROTATION rotation;<br>
> + DISPLAYCONFIG_SCALING scaling;<br>
> + DISPLAYCONFIG_RATIONAL refreshRate;<br>
> + DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;<br>
> + BOOL targetAvailable;<br>
> + UINT32 statusFlags;<br>
> +};<br>
> +<br>
> +struct DISPLAYCONFIG_PATH_INFO {<br>
> + DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;<br>
> + DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;<br>
> + UINT32 flags;<br>
> +};<br>
> +<br>
> +<br>
> +enum D3DKMT_ESCAPETYPE {<br>
> + D3DKMT_ESCAPE_DRIVERPRIVATE = 0<br>
> +};<br>
> +<br>
> +struct D3DDDI_ESCAPEFLAGS {<br>
> + union {<br>
> + struct {<br>
> + UINT Reserved : 31;<br>
> + };<br>
> + UINT Value;<br>
> + };<br>
> +};<br>
> +<br>
> +struct D3DKMT_ESCAPE {<br>
> + D3DKMT_HANDLE hAdapter;<br>
> + D3DKMT_HANDLE hDevice;<br>
> + D3DKMT_ESCAPETYPE Type;<br>
> + D3DDDI_ESCAPEFLAGS Flags;<br>
> + VOID* pPrivateDriverData;<br>
> + UINT PrivateDriverDataSize;<br>
> + D3DKMT_HANDLE hContext;<br>
> +};<br>
> +<br>
> +typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;<br>
> +<br>
> +struct D3DKMT_OPENADAPTERFROMHDC {<br>
> + HDC hDc;<br>
> + D3DKMT_HANDLE hAdapter;<br>
> + LUID AdapterLuid;<br>
> + D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;<br>
> +};<br>
> +<br>
> +struct D3DKMT_CLOSEADAPTER {<br>
> + D3DKMT_HANDLE hAdapter;<br>
> +};<br>
> +<br>
> +struct D3DKMT_OPENADAPTERFROMDEVICENAME {<br>
> + PCWSTR pDeviceName;<br>
> + D3DKMT_HANDLE hAdapter;<br>
> + LUID AdapterLuid;<br>
> +};<br>
> +<br>
> +struct D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME {<br>
> + WCHAR DeviceName[32];<br>
> + D3DKMT_HANDLE hAdapter;<br>
> + LUID AdapterLuid;<br>
> + D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;<br>
> +};<br>
> +<br>
<br>
</div></div>There are defined from Microsoft, better to move them in<br>
a separate file. The license can changed easier.<br></blockquote><div> </div><div>Can you please further explain regarding the licensing? which license should be used?</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<div><div class="h5"><br>
> +struct QXLMonitorEscape {<br>
> + QXLMonitorEscape(DEVMODE* dev_mode)<br>
> + {<br>
> + ZeroMemory(&_head, sizeof(_head));<br>
> + _head.x = dev_mode->dmPosition.x;<br>
> + _head.y = dev_mode->dmPosition.y;<br>
> + _head.width = dev_mode->dmPelsWidth;<br>
> + _head.height = dev_mode->dmPelsHeight;<br>
> + }<br>
> + QXLHead _head;<br>
> +};<br>
> +<br>
> +struct QxlCustomEscapeObj : public QXLEscapeSetCustomDisplay {<br>
> + QxlCustomEscapeObj(uint32_t bitsPerPel, uint32_t width, uint32_t height)<br>
> + {<br>
> + xres = width;<br>
> + yres = height;<br>
> + bpp = bitsPerPel;<br>
> + }<br>
> + QxlCustomEscapeObj() {};<br>
> +};<br>
> +<br>
> +struct WDDMCustomDisplayEscape {<br>
> + WDDMCustomDisplayEscape(DEVMODE* dev_mode)<br>
> + {<br>
> + _ioctl = QXL_ESCAPE_SET_CUSTOM_DISPLAY;<br>
> + _custom.bpp = dev_mode->dmBitsPerPel;<br>
> + _custom.xres = dev_mode->dmPelsWidth;<br>
> + _custom.yres = dev_mode->dmPelsHeight;<br>
> + }<br>
> + int _ioctl;<br>
> + QXLEscapeSetCustomDisplay _custom;<br>
> +};<br>
> +<br>
> +struct WDDMMonitorConfigEscape {<br>
> + WDDMMonitorConfigEscape(DisplayMode* mode)<br>
> + {<br>
> + _ioctl = QXL_ESCAPE_MONITOR_CONFIG;<br>
> + _<a href="http://head.id" rel="noreferrer" target="_blank">head.id</a> = _head.surface_id = 0;<br>
> + _head.x = mode->get_pos_x();<br>
> + _head.y = mode->get_pos_y();<br>
> + _head.width = mode->get_width();<br>
> + _head.height = mode->get_height();<br>
> + }<br>
> + int _ioctl;<br>
> + QXLHead _head;<br>
> +};<br>
> +<br>
> +DisplayConfig* DisplayConfig::create_config()<br>
> +{<br>
> + DisplayConfig* new_interface;<br>
> + //Try to open a WDDM adapter.<br>
> + new_interface = new WDDMInterface();<br>
> + if(new_interface->type() == WDDM) {<br>
> + return new_interface;<br>
> + }<br>
> + //If that failed so clean up and assume we have an XPDM driver<br>
> + delete new_interface;<br>
> +<br>
> + new_interface = new XPDMInterface();<br>
> + return new_interface;<br>
> +}<br>
> +<br>
> +DisplayConfig::DisplayConfig()<br>
> + : _driver_type(INVALID_DRIVER)<br>
> + , _send_monitors_config(false)<br>
> +{}<br>
> +<br>
> +bool XPDMInterface::is_attached(DISPLAY_DEVICE* dev_info)<br>
> +{<br>
> + return !!(dev_info->StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP);<br>
> +}<br>
> +<br>
> +bool XPDMInterface::set_monitor_state(LPCTSTR device_name, DEVMODE*<br>
> dev_mode, MONITOR_STATE state)<br>
> +{<br>
> + dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;<br>
> + if (state == MONITOR_ATTACHED) {<br>
> + return true;<br>
> + }<br>
> +<br>
> + LONG status = ChangeDisplaySettingsEx(device_name, dev_mode, NULL,<br>
> CDS_UPDATEREGISTRY, NULL);<br>
> + return (status == DISP_CHANGE_SUCCESSFUL);<br>
> +}<br>
> +<br>
> +LONG XPDMInterface::update_display_settings()<br>
> +{<br>
> + return ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);<br>
> +}<br>
> +<br>
> +bool XPDMInterface::update_dev_mode_position(LPCTSTR device_name,<br>
> + DEVMODE* dev_mode, LONG x, LONG<br>
> y)<br>
> +{<br>
> + //Convert the position so that the primary is always at (0,0)<br>
> + dev_mode->dmPosition.x = x;<br>
> + dev_mode->dmPosition.y = y;<br>
> + dev_mode->dmFields |= DM_POSITION;<br>
> + vd_printf("%s: setting %S at (%lu, %lu)", __FUNCTION__, device_name,<br>
> dev_mode->dmPosition.x,<br>
> + dev_mode->dmPosition.y);<br>
> +<br>
> + LONG status = ChangeDisplaySettingsEx(device_name, dev_mode, NULL,<br>
> + CDS_UPDATEREGISTRY | CDS_NORESET,<br>
> NULL);<br>
> + return (status == DISP_CHANGE_SUCCESSFUL);<br>
> +}<br>
> +<br>
> +bool XPDMInterface::custom_display_escape(LPCTSTR device_name, DEVMODE*<br>
> dev_mode)<br>
> +{<br>
> + LONG ret;<br>
> + NTSTATUS Status (ERROR_SUCCESS);<br>
> + HDC hdc = CreateDC(device_name, NULL, NULL, NULL);<br>
> +<br>
> + if (!hdc) {<br>
> + ret = ChangeDisplaySettingsEx(device_name, dev_mode, NULL,<br>
> CDS_UPDATEREGISTRY, NULL);<br>
> + if (ret == DISP_CHANGE_BADMODE) {<br>
> + // custom resolution might not be set yet, use known resolution<br>
> + // FIXME: this causes client temporary resize... a<br>
> + // solution would involve passing custom resolution before<br>
> + // driver initialization, perhaps through registry<br>
> + dev_mode->dmPelsWidth = 640;<br>
> + dev_mode->dmPelsHeight = 480;<br>
> + ret = ChangeDisplaySettingsEx(device_name, dev_mode, NULL,<br>
> CDS_UPDATEREGISTRY, NULL);<br>
> + }<br>
> +<br>
> + vd_printf("attach %ld", ret);<br>
> + if (!(hdc = CreateDC(device_name, NULL, NULL, NULL))) {<br>
> + vd_printf("%s: failed to create DC", __FUNCTION__);<br>
> + return false;<br>
> + }<br>
> + }<br>
> +<br>
> + QxlCustomEscapeObj custom_escape(dev_mode->dmBitsPerPel,<br>
> + dev_mode->dmPelsWidth,<br>
> dev_mode->dmPelsHeight);<br>
> +<br>
> + int err = ExtEscape(hdc, QXL_ESCAPE_SET_CUSTOM_DISPLAY,<br>
> + sizeof(QXLEscapeSetCustomDisplay), (LPCSTR) &custom_escape, 0,<br>
> NULL);<br>
> + if (err <= 0) {<br>
> + vd_printf("%s: Can't set custom display, perhaps running with an<br>
> older driver?",<br>
> + __FUNCTION__);<br>
> + }<br>
> +<br>
> + if (!find_best_mode(device_name, dev_mode)) {<br>
> + Status = E_FAIL;<br>
> + }<br>
> +<br>
> + DeleteDC(hdc);<br>
> + return NT_SUCCESS(Status);<br>
> +}<br>
> +<br>
> +bool XPDMInterface::update_monitor_config(LPCTSTR device_name, DisplayMode*<br>
> mode,<br>
> + DEVMODE* dev_mode)<br>
> +{<br>
> + if (!mode || !mode->get_attached()) {<br>
> + return false;<br>
> + }<br>
> +<br>
> + QXLMonitorEscape monitor_config(dev_mode);<br>
> + HDC hdc(CreateDC(device_name, NULL, NULL, NULL));<br>
> + int err(0);<br>
> +<br>
> + if (!hdc || !_send_monitors_config) {<br>
> + return false;<br>
> + }<br>
> +<br>
> + err = ExtEscape(hdc, QXL_ESCAPE_MONITOR_CONFIG, sizeof(QXLHead),<br>
> + (LPCSTR) &monitor_config, 0, NULL);<br>
> + if (err < 0) {<br>
> + vd_printf("%s: %S can't update monitor config, may have old, old<br>
> driver",<br>
> + __FUNCTION__, device_name);<br>
> + }<br>
> + DeleteDC(hdc);<br>
> + return (err >= 0);<br>
> +}<br>
> +<br>
> +bool XPDMInterface::find_best_mode(LPCTSTR Device, DEVMODE* dev_mode)<br>
> +{<br>
> + DWORD closest_diff = -1;<br>
> + DWORD best = -1;<br>
> +<br>
> + // force refresh mode table<br>
> + DEVMODE test_dev_mode;<br>
> + ZeroMemory(&test_dev_mode, sizeof(test_dev_mode));<br>
> + test_dev_mode.dmSize = sizeof(DEVMODE);<br>
> + EnumDisplaySettings(Device, 0xffffff, &test_dev_mode);<br>
> +<br>
> + //Find the closest size which will fit within the monitor<br>
> + for (DWORD i = 0; EnumDisplaySettings(Device, i, &test_dev_mode); i++) {<br>
> + if (dev_mode->dmPelsWidth > test_dev_mode.dmPelsWidth ||<br>
> + dev_mode->dmPelsHeight > test_dev_mode.dmPelsHeight ||<br>
> + dev_mode->dmBitsPerPel != test_dev_mode.dmBitsPerPel) {<br>
> + continue;<br>
> + }<br>
> + DWORD wdiff = dev_mode->dmPelsWidth - test_dev_mode.dmPelsWidth;<br>
> + DWORD hdiff = dev_mode->dmPelsHeight - test_dev_mode.dmPelsHeight;<br>
> + DWORD diff = wdiff * wdiff + hdiff * hdiff;<br>
> + if (diff < closest_diff) {<br>
> + closest_diff = diff;<br>
> + best = i;<br>
> + }<br>
> + }<br>
> + vd_printf("%s: closest_diff at %lu best %lu", __FUNCTION__,<br>
> closest_diff, best);<br>
> + if (best == (DWORD) -1 || !EnumDisplaySettings(Device, best, dev_mode))<br>
> {<br>
> + return false;<br>
> + }<br>
> +<br>
> + //Change to the best fit<br>
> + LONG status = ChangeDisplaySettingsEx(Device, dev_mode, NULL,<br>
> + CDS_UPDATEREGISTRY | CDS_NORESET,<br>
> NULL);<br>
> + return NT_SUCCESS(status);<br>
> +}<br>
> +<br>
> +WDDMInterface::WDDMInterface()<br>
> + : _pfnOpen_adapter_hdc(NULL)<br>
> + , _pfnClose_adapter(NULL)<br>
> + , _pfnEscape(NULL)<br>
> + , _pfnOpen_adapter_device_name(NULL)<br>
> + , _pfnOpen_adapter_gdi_name(NULL)<br>
> +{<br>
> + _driver_type = INVALID_DRIVER;<br>
> +<br>
> + //Did the CCD load?<br>
> + if (_ccd.error() == ERROR_NOT_SUPPORTED) {<br>
> + return;<br>
> + }<br>
> +<br>
> + //Can we find the D3D calls we need?<br>
> + if (!init_d3d_api()) {<br>
> + return;<br>
> + }<br>
> +<br>
> + //Initialize CCD path stuff<br>
> + if (!_ccd.query_display_config()) {<br>
> + return;;<br>
> + }<br>
> + if (!_ccd.set_display_config()) {<br>
> + return;<br>
> + }<br>
> + _driver_type = WDDM;<br>
> +}<br>
> +<br>
> +WDDMInterface::~WDDMInterface()<br>
> +{<br>
> + if (_driver_type != WDDM) {<br>
> + vd_printf("%s called with invalid driver type of %d", __FUNCTION__,<br>
> _driver_type);<br>
> + return;<br>
> + }<br>
> +}<br>
> +<br>
> +bool WDDMInterface::is_attached(DISPLAY_DEVICE* dev_info)<br>
> +{<br>
> + return _ccd.is_attached(dev_info->DeviceName);<br>
> +}<br>
> +<br>
> +bool WDDMInterface::set_monitor_state(LPCTSTR device_name, DEVMODE*<br>
> dev_mode, MONITOR_STATE state)<br>
> +{<br>
> + return _ccd.set_path_state(device_name, state);<br>
> +}<br>
> +<br>
> +bool WDDMInterface::custom_display_escape(LPCTSTR device_name, DEVMODE*<br>
> dev_mode)<br>
> +{<br>
> + DISPLAYCONFIG_MODE_INFO* mode = _ccd.get_active_mode(device_name,<br>
> false);<br>
> + if (!mode) {<br>
> + return false;<br>
> + }<br>
> +<br>
> + //Don't bother if we are already set to the new resolution<br>
> + if (mode->sourceMode.width == dev_mode->dmPelsWidth &&<br>
> + mode->sourceMode.height == dev_mode->dmPelsHeight) {<br>
> + return true;<br>
> + }<br>
> +<br>
> + vd_printf("%s: updating %S resolution\n", __FUNCTION__, device_name);<br>
> +<br>
> + WDDMCustomDisplayEscape wddm_escape(dev_mode);<br>
> + if (escape(device_name, &wddm_escape, sizeof(wddm_escape))) {<br>
> + return _ccd.update_mode_size(device_name, dev_mode);<br>
> + }<br>
> +<br>
> + vd_printf("%s: (%dx%d)", __FUNCTION__, mode->sourceMode.width,<br>
> mode->sourceMode.height);<br>
> + return false;<br>
> +}<br>
> +<br>
> +bool WDDMInterface::update_monitor_config(LPCTSTR device_name, DisplayMode*<br>
> display_mode,<br>
> + DEVMODE* dev_mode)<br>
> +{<br>
> + if (!display_mode || !display_mode->get_attached()) {<br>
> + return false;<br>
> + }<br>
> + DISPLAYCONFIG_MODE_INFO* mode = _ccd.get_active_mode(device_name,<br>
> false);<br>
> + if (!mode || !_send_monitors_config)<br>
> + return false;<br>
> +<br>
> + WDDMMonitorConfigEscape wddm_escape(display_mode);<br>
> + if (escape(device_name, &wddm_escape, sizeof(wddm_escape))) {<br>
> + //Update the path position<br>
> + return _ccd.update_mode_position(device_name, dev_mode);<br>
> + }<br>
> +<br>
> + vd_printf("%s: %S failed", __FUNCTION__, device_name);<br>
> + return false;<br>
> +<br>
> +}<br>
> +<br>
> +LONG WDDMInterface::update_display_settings()<br>
> +{<br>
> + //If we removed the primary monitor since the last call, we need to<br>
> + //reorder the other monitors, making the leftmost one the primary<br>
> + _ccd.verify_primary_position();<br>
> +<br>
> + if (!_ccd.set_display_config()) {<br>
> + if (_ccd._error != ERROR_INVALID_PARAMETER) {<br>
> + vd_printf("%s: set_display_config failed", __FUNCTION__);<br>
> + } else {<br>
> + vd_printf("%s: Invalid parameter!", __FUNCTION__);<br>
> + _ccd.debug_print_config("After error");<br>
> + }<br>
> + }<br>
> + return _ccd.error();<br>
> +}<br>
> +<br>
> +void WDDMInterface::update_config_path()<br>
> +{<br>
> + _ccd.query_display_config();<br>
> +}<br>
> +<br>
> +bool WDDMInterface::update_dev_mode_position(LPCTSTR device_name, DEVMODE*<br>
> dev_mode,<br>
> + LONG x, LONG y)<br>
> +{<br>
> + //Convert the position so that the primary is always at (0,0)<br>
> + dev_mode->dmPosition.x = x;<br>
> + dev_mode->dmPosition.y = y;<br>
> + _ccd.update_mode_position(device_name, dev_mode);<br>
> + return _ccd.update_mode_position(device_name, dev_mode);<br>
> +}<br>
> +<br>
> +bool WDDMInterface::init_d3d_api()<br>
> +{<br>
> + HMODULE hModule = LoadLibrary(L"gdi32.dll");<br>
> +<br>
> + //Look for the gdi32 functions we need to perform driver escapes<br>
> + if (!hModule) {<br>
> + vd_printf("%s something wildly wrong as we can't open gdi32.dll",<br>
> __FUNCTION__);<br>
> + _driver_type = INVALID_DRIVER;<br>
> + return false;<br>
> + }<br>
> +<br>
> + do {<br>
> + _pfnClose_adapter = (PFND3DKMT_CLOSEADAPTER)<br>
> + GetProcAddress(hModule, "D3DKMTCloseAdapter");<br>
> + if (!_pfnClose_adapter) {<br>
> + break;<br>
> + }<br>
> +<br>
> + _pfnEscape = (PFND3DKMT_ESCAPE) GetProcAddress(hModule,<br>
> "D3DKMTEscape");<br>
> + if (!_pfnEscape) {<br>
> + break;<br>
> + }<br>
> +<br>
> + _pfnOpen_adapter_hdc = (PFND3DKMT_OPENADAPTERFROMHDC)<br>
> + GetProcAddress(hModule, "D3DKMTOpenAdapterFromHdc");<br>
> + if (!_pfnOpen_adapter_hdc) {<br>
> + break;<br>
> + }<br>
> +<br>
> + _pfnOpen_adapter_device_name = (PFND3DKMT_OPENADAPTERFROMDEVICENAME)<br>
> + GetProcAddress(hModule, "D3DKMTOpenAdapterFromDeviceName");<br>
> + if (!_pfnOpen_adapter_device_name) {<br>
> + break;<br>
> + }<br>
> +<br>
> + _pfnOpen_adapter_gdi_name =<br>
> (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)<br>
> + GetProcAddress(hModule, "D3DKMTOpenAdapterFromGdiDisplayName");<br>
> + if (!_pfnOpen_adapter_gdi_name) {<br>
> + break;<br>
> + }<br>
> +<br>
> + }<br>
> + while(0);<br>
> +<br>
> + FreeLibrary(hModule);<br>
> +<br>
> + //Did we get them ?<br>
> + if (!_pfnClose_adapter || !_pfnOpen_adapter_hdc || !_pfnEscape) {<br>
> + return false;<br>
> + }<br>
> + _driver_type = WDDM;<br>
> + return true;<br>
> +}<br>
> +<br>
> +D3DKMT_HANDLE WDDMInterface::adapter_handle(LPCTSTR device_name)<br>
> +{<br>
> + D3DKMT_HANDLE hAdapter(0);<br>
> +<br>
> + //For some reason, unknown to me, this call will occasionally fail.<br>
> + if ((hAdapter = handle_from_DC(device_name))) {<br>
> + return hAdapter;<br>
> + }<br>
> + //So try other available methods.<br>
> + if (_pfnOpen_adapter_device_name && (hAdapter =<br>
> handle_from_device_name(device_name))) {<br>
> + return hAdapter;<br>
> + }<br>
> + //One last chance to open this guy<br>
> + if (_pfnOpen_adapter_gdi_name) {<br>
> + hAdapter = handle_from_GDI_name(device_name);<br>
> + }<br>
> +<br>
> + if (!hAdapter) {<br>
> + vd_printf("%s: failed to open adapter %S", __FUNCTION__,<br>
> device_name);<br>
> + }<br>
> +<br>
> + return hAdapter;<br>
> +}<br>
> +<br>
> +D3DKMT_HANDLE WDDMInterface::handle_from_DC(LPCTSTR adapter_name)<br>
> +{<br>
> + NTSTATUS status;<br>
> + D3DKMT_OPENADAPTERFROMHDC open_data;<br>
> + HDC hDc(CreateDC(adapter_name, NULL, NULL, NULL));<br>
> +<br>
> + if (!hDc) {<br>
> + vd_printf("%s: %S CreateDC failed with %lu", __FUNCTION__,<br>
> adapter_name, GetLastError());<br>
> + return 0;<br>
> + }<br>
> +<br>
> + ZeroMemory(&open_data, sizeof(D3DKMT_OPENADAPTERFROMHDC));<br>
> + open_data.hDc = hDc;<br>
> +<br>
> + if (!NT_SUCCESS(status = _pfnOpen_adapter_hdc(&open_data))) {<br>
> + vd_printf("%s: %S open adapter from hdc failed with %lu",<br>
> __FUNCTION__, adapter_name,<br>
> + status);<br>
> + open_data.hAdapter = 0;<br>
> + }<br>
> +<br>
> + DeleteDC(hDc);<br>
> + return open_data.hAdapter;<br>
> +}<br>
> +<br>
> +D3DKMT_HANDLE WDDMInterface::handle_from_device_name(LPCTSTR adapter_name)<br>
> +{<br>
> + D3DKMT_OPENADAPTERFROMDEVICENAME display_name_data;<br>
> + NTSTATUS status;<br>
> +<br>
> + ZeroMemory(&display_name_data, sizeof(display_name_data));<br>
> + display_name_data.pDeviceName = adapter_name;<br>
> +<br>
> + if (NT_SUCCESS(status =<br>
> _pfnOpen_adapter_device_name(&display_name_data))) {<br>
> + return display_name_data.hAdapter;<br>
> + }<br>
> +<br>
> + vd_printf("%s %S failed with 0x%lx", __FUNCTION__, adapter_name,<br>
> status);<br>
> + return 0;<br>
> +}<br>
> +<br>
> +D3DKMT_HANDLE WDDMInterface::handle_from_GDI_name(LPCTSTR adapter_name)<br>
> +{<br>
> + D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME gdi_display_name;<br>
> + NTSTATUS status;<br>
> +<br>
> + ZeroMemory(&gdi_display_name, sizeof(gdi_display_name));<br>
> + memcpy((void *) gdi_display_name.DeviceName, adapter_name,<br>
> sizeof(TCHAR)* CCHDEVICENAME);<br>
> +<br>
> + if (NT_SUCCESS(status = _pfnOpen_adapter_gdi_name(&gdi_display_name))) {<br>
> + return gdi_display_name.hAdapter;<br>
> + }<br>
> +<br>
> + vd_printf("%s: %S aurrrgghh nothing works..error is 0x%lx",<br>
> __FUNCTION__, adapter_name,<br>
> + status);<br>
> + return 0;<br>
> +}<br>
> +<br>
> +void WDDMInterface::close_adapter(D3DKMT_HANDLE handle)<br>
> +{<br>
> + D3DKMT_CLOSEADAPTER closeData;<br>
> + if (handle) {<br>
> + closeData.hAdapter = handle;<br>
> + _pfnClose_adapter(&closeData);<br>
> + }<br>
> +}<br>
> +<br>
> +bool WDDMInterface::escape(LPCTSTR device_name, void* data, UINT size_data)<br>
> +{<br>
> + D3DKMT_ESCAPE escapeData;<br>
> + NTSTATUS status;<br>
> + D3DKMT_HANDLE hAdapter(0);<br>
> +<br>
> + if (!(hAdapter = adapter_handle(device_name)))<br>
> + return false;<br>
> +<br>
> + escapeData.hAdapter = hAdapter;<br>
> + escapeData.hDevice = 0;<br>
> + escapeData.hContext = 0;<br>
> + escapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;<br>
> + escapeData.Flags.Value = 0;<br>
> + escapeData.pPrivateDriverData = data;<br>
> + escapeData.PrivateDriverDataSize = size_data;<br>
> +<br>
> + status = _pfnEscape(&escapeData);<br>
> +<br>
> + if (!NT_SUCCESS(status)) {<br>
> + vd_printf("%s: this should never happen. Status is 0x%lx",<br>
> __FUNCTION__, status);<br>
> + _driver_type = INVALID_DRIVER;<br>
> + }<br>
> +<br>
> + //Close the handle to this device<br>
> + close_adapter(hAdapter);<br>
> + return NT_SUCCESS(status);<br>
> +}<br>
> +<br>
> +CCD::CCD()<br>
> + :_NumPathElements(0)<br>
> + ,_NumModeElements(0)<br>
> + ,_pPathInfo(NULL)<br>
> + ,_pModeInfo(NULL)<br>
> + ,_pfnGetDeviceInfo(NULL)<br>
> + ,_pfnGetDisplayConfigBufferSizes(NULL)<br>
> + ,_pfnQueryDisplayConfig(NULL)<br>
> + ,_pfnSetDisplayConfig(NULL)<br>
> + ,_error(0)<br>
> + ,_primary_detached(false)<br>
> + ,_path_state(PATH_UPDATED)<br>
> +{<br>
> + if (load_api()) {<br>
> + get_config_buffers();<br>
> + }<br>
> +}<br>
> +<br>
> +CCD::~CCD()<br>
> +{<br>
> + free_config_buffers();<br>
> +}<br>
> +<br>
> +bool CCD::query_display_config()<br>
> +{<br>
> + LONG query_error(ERROR_SUCCESS);<br>
> +<br>
> + //Until we get it or error != ERROR_INSUFFICIENT_BUFFER<br>
> + do {<br>
> + query_error = _pfnQueryDisplayConfig(QDC_ALL_PATHS,<br>
> &_NumPathElements, _pPathInfo,<br>
> + &_NumModeElements, _pModeInfo, NULL);<br>
> +<br>
> + // if ERROR_INSUFFICIENT_BUFFER need to retry QueryDisplayConfig<br>
> + // to get a new set of config buffers<br>
> + //(see<br>
> <a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff569215(v=vs.85).aspx" rel="noreferrer" target="_blank">https://msdn.microsoft.com/en-us/library/windows/hardware/ff569215(v=vs.85).aspx</a><br>
> )<br>
> + if (query_error) {<br>
> + if (query_error == ERROR_INSUFFICIENT_BUFFER) {<br>
> + free_config_buffers();<br>
> + if (!get_config_buffers())<br>
> + return false;<br>
> + } else {<br>
> + _error = query_error;<br>
> + vd_printf("%s failed QueryDisplayConfig with 0x%lx",<br>
> __FUNCTION__, _error);<br>
> + return false;<br>
> + }<br>
> + }<br>
> + } while(query_error);<br>
> + _path_state = PATH_CURRENT;<br>
> + return true;<br>
> +}<br>
> +<br>
> +DISPLAYCONFIG_MODE_INFO* CCD::get_active_mode(LPCTSTR device_name, bool<br>
> return_on_error)<br>
> +{<br>
> + DISPLAYCONFIG_PATH_INFO* active_path;<br>
> +<br>
> + active_path = get_device_path(device_name, true);<br>
> +<br>
> + if (!active_path ) {<br>
> + vd_printf("%s:%S failed", __FUNCTION__, device_name);<br>
> + return NULL;<br>
> + }<br>
> + return &_pModeInfo[active_path->sourceInfo.modeInfoIdx];<br>
> +}<br>
> +<br>
> +bool CCD::set_display_config() {<br>
> +<br>
> + debug_print_config("Before SetDisplayConfig");<br>
> +<br>
> + if (_path_state == PATH_CURRENT) {<br>
> + vd_printf("%s: path states says nothing changed", __FUNCTION__);<br>
> + return true;<br>
> + }<br>
> +<br>
> + if (!(_error = _pfnSetDisplayConfig(_NumPathElements, _pPathInfo,<br>
> + _NumModeElements, _pModeInfo,<br>
> + SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG |<br>
> SDC_FORCE_MODE_ENUMERATION))) {<br>
> + return true;<br>
> + }<br>
> +<br>
> + vd_printf("%s failed SetDisplayConfig with 0x%lx", __FUNCTION__,<br>
> _error);<br>
> + debug_print_config("After failed SetDisplayConfig");<br>
> + return false;<br>
> +}<br>
> +<br>
> +DISPLAYCONFIG_PATH_INFO* CCD::get_device_path(LPCTSTR device_name, bool<br>
> bActive)<br>
> +{<br>
> + //Search for device's active path<br>
> + for (UINT32 i = 0; i < _NumPathElements; i++) {<br>
> + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i];<br>
> +<br>
> + //if bActive, return only paths that are currently active<br>
> + if (bActive && !is_active_path(path_info))<br>
> + continue;<br>
> + if (!is_device_path(device_name, path_info))<br>
> + continue;<br>
> + return path_info;<br>
> + }<br>
> + _error = ERROR_GEN_FAILURE;<br>
> + return NULL;<br>
> +}<br>
> +<br>
> +void CCD::debug_print_config(const char* prefix)<br>
> +{<br>
> + TCHAR dev_name[CCHDEVICENAME];<br>
> + for (UINT32 i = 0; i < _NumPathElements; i++) {<br>
> + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i];<br>
> + if (!(path_info->flags & DISPLAYCONFIG_PATH_ACTIVE))<br>
> + continue;<br>
> + get_device_name_config(path_info, dev_name);<br>
> +<br>
> + if (path_info->sourceInfo.modeInfoIdx ==<br>
> DISPLAYCONFIG_PATH_MODE_IDX_INVALID) {<br>
> + vd_printf("%s: %S [%s] This path is active but has invalid mode<br>
> set.", __FUNCTION__,<br>
> + dev_name, prefix);<br>
> + continue;<br>
> + }<br>
> + DISPLAYCONFIG_MODE_INFO* mode =<br>
> &_pModeInfo[path_info->sourceInfo.modeInfoIdx];<br>
> + vd_printf("%s: %S [%s] (%ld,%ld) (%ux%u).", __FUNCTION__, dev_name,<br>
> prefix,<br>
> + mode->sourceMode.position.x, mode->sourceMode.position.y,<br>
> + mode->sourceMode.width, mode->sourceMode.height);<br>
> + }<br>
> +}<br>
> +<br>
> +bool CCD::load_api()<br>
> +{<br>
> + HMODULE hModule = LoadLibrary(L"user32.dll");<br>
> + if(!hModule) {<br>
> + return false;<br>
> + }<br>
> +<br>
> + bool bFound_all(false);<br>
> + do {<br>
> + if (!(_pfnGetDeviceInfo = (PDISPLAYCONFIG_GETDEVICEINFO)<br>
> + GetProcAddress(hModule, "DisplayConfigGetDeviceInfo"))) {<br>
> + break;<br>
> + }<br>
> +<br>
> + if (!(_pfnGetDisplayConfigBufferSizes =<br>
> (PGETDISPLAYCONFIG_BUFFERSIZES)<br>
> + GetProcAddress(hModule, "GetDisplayConfigBufferSizes"))) {<br>
> + break;<br>
> + }<br>
> +<br>
> + if (!(_pfnQueryDisplayConfig = (PQUERYDISPLAYCONFIG)<br>
> + GetProcAddress(hModule, "QueryDisplayConfig"))) {<br>
> + break;<br>
> + }<br>
> +<br>
> + if (!(_pfnSetDisplayConfig = (PSETDISPLAYCONFIG)<br>
> + GetProcAddress(hModule, "SetDisplayConfig"))) {<br>
> + break;<br>
> + }<br>
> + bFound_all = true;<br>
> + }<br>
> + while(0);<br>
> +<br>
> + FreeLibrary(hModule);<br>
> + return bFound_all;<br>
> +}<br>
> +<br>
> +bool CCD::get_config_buffers()<br>
> +{<br>
> + //Get Config Buffer Sizes<br>
> + free_config_buffers();<br>
> + _error = _pfnGetDisplayConfigBufferSizes(QDC_ALL_PATHS,<br>
> &_NumPathElements,<br>
> + &_NumModeElements);<br>
> + if (_error) {<br>
> + vd_printf("%s: GetDisplayConfigBufferSizes failed with 0x%lx",<br>
> __FUNCTION__, _error);<br>
> + return false;<br>
> + }<br>
> +<br>
> + //Allocate arrays<br>
> + _pPathInfo = ((DISPLAYCONFIG_PATH_INFO*)<br>
> malloc(sizeof(DISPLAYCONFIG_PATH_INFO) * _NumPathElements));<br>
> + _pModeInfo = ((DISPLAYCONFIG_MODE_INFO*)<br>
> malloc(sizeof(DISPLAYCONFIG_MODE_INFO) * _NumModeElements));<br>
> +<br>
> + if (!_pPathInfo || !_pModeInfo) {<br>
> + vd_printf("%s OOM ", __FUNCTION__);<br>
> + return false;<br>
> + }<br>
> +<br>
> + ///clear the above arrays<br>
> + ZeroMemory(_pPathInfo, sizeof(DISPLAYCONFIG_PATH_INFO) *<br>
> _NumPathElements);<br>
> + ZeroMemory(_pModeInfo, sizeof(DISPLAYCONFIG_MODE_INFO) *<br>
> _NumModeElements);<br>
> + return true;<br>
> +}<br>
> +<br>
> +void CCD::free_config_buffers()<br>
> +{<br>
> + if (_pModeInfo) {<br>
> + free(_pModeInfo);<br>
> + _pModeInfo = NULL;<br>
> + }<br>
> + if (_pPathInfo) {<br>
> + free(_pPathInfo);<br>
> + _pPathInfo = NULL;<br>
> + }<br>
> + _NumModeElements = _NumPathElements = 0;<br>
> +}<br>
> +<br>
> +bool CCD::get_device_name_config(DISPLAYCONFIG_PATH_INFO* path, LPCTSTR<br>
> dev_name)<br>
> +{<br>
> + DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name;<br>
> + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;<br>
> + source_name.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);<br>
> + source_name.header.adapterId = path->sourceInfo.adapterId;<br>
> + <a href="http://source_name.header.id" rel="noreferrer" target="_blank">source_name.header.id</a> = path->sourceInfo.id;<br>
> +<br>
> + _error = _pfnGetDeviceInfo(&source_name.header);<br>
> + if (_error) {<br>
> + vd_printf("%s DisplayConfigGetDeviceInfo failed with %lu",<br>
> __FUNCTION__, _error);<br>
> + return false;<br>
> + }<br>
> + memcpy((void *)dev_name, source_name.viewGdiDeviceName, CCHDEVICENAME*<br>
> sizeof(TCHAR));<br>
> + return true;<br>
> +}<br>
> +<br>
> +bool CCD::is_device_path(LPCTSTR device_name, DISPLAYCONFIG_PATH_INFO* path)<br>
> +{<br>
> + //Does this path belong to device_name?<br>
> + TCHAR dev_name[CCHDEVICENAME];<br>
> + if (!get_device_name_config(path, dev_name)) {<br>
> + return false;<br>
> + }<br>
> + if (_tcscmp(dev_name, device_name)) {<br>
> + return false;<br>
> + }<br>
> + return true;<br>
> +}<br>
> +<br>
> +// If we have detached the primary monitor, then we need to reset the<br>
> positions of the remaining<br>
> +// monitors to insure that at least one is positioned at (0,0)<br>
> +bool CCD::verify_primary_position()<br>
> +{<br>
> + LONG leftmost_x(0);<br>
> + if (!_primary_detached) {<br>
> + return true;<br>
> + }<br>
> + _primary_detached = false;<br>
> +<br>
> + for (UINT32 i = 0; i < _NumPathElements; i++) {<br>
> + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i];<br>
> + if (!(path_info->flags & DISPLAYCONFIG_PATH_ACTIVE))<br>
> + continue;<br>
> +<br>
> + DISPLAYCONFIG_MODE_INFO* mode =<br>
> &_pModeInfo[path_info->sourceInfo.modeInfoIdx];<br>
> + if (leftmost_x > mode->sourceMode.position.x) {<br>
> + leftmost_x = mode->sourceMode.position.x;<br>
> + }<br>
> + }<br>
> +<br>
> + if (leftmost_x == 0) {<br>
> + return false;<br>
> + }<br>
> +<br>
> + for (UINT32 i = 0; i < _NumPathElements; i++) {<br>
> + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i];<br>
> + if ((!(path_info->flags & DISPLAYCONFIG_PATH_ACTIVE)))<br>
> + continue;<br>
> + DISPLAYCONFIG_MODE_INFO* mode =<br>
> &_pModeInfo[path_info->sourceInfo.modeInfoIdx];<br>
> + vd_printf("%s: setting mode x to %lu", __FUNCTION__,<br>
> mode->sourceMode.position.x);<br>
> + mode->sourceMode.position.x -= leftmost_x;<br>
> + }<br>
> + _path_state = PATH_UPDATED;<br>
> + return true;<br>
> +}<br>
> +<br>
> +bool CCD::update_mode_position(LPCTSTR device_name, DEVMODE* dev_mode)<br>
> +{<br>
> + DISPLAYCONFIG_MODE_INFO* mode = get_active_mode(device_name, false);<br>
> + if (!mode)<br>
> + return false;<br>
> +<br>
> + mode->sourceMode.position.x = dev_mode->dmPosition.x;<br>
> + mode->sourceMode.position.y = dev_mode->dmPosition.y;<br>
> + vd_printf("%s: %S updated path mode to (%lu, %lu) - (%u x%u)",<br>
> __FUNCTION__,<br>
> + device_name,<br>
> + mode->sourceMode.position.x, mode->sourceMode.position.y,<br>
> + mode->sourceMode.width, mode->sourceMode.height);<br>
> + _path_state = PATH_UPDATED;<br>
> + return true;<br>
> +<br>
> +}<br>
> +<br>
> +bool CCD::update_mode_size(LPCTSTR device_name, DEVMODE* dev_mode)<br>
> +{<br>
> + DISPLAYCONFIG_MODE_INFO* mode = get_active_mode(device_name, false);<br>
> + if (!mode) {<br>
> + return false;<br>
> + }<br>
> +<br>
> + mode->sourceMode.width = dev_mode->dmPelsWidth;<br>
> + mode->sourceMode.height = dev_mode->dmPelsHeight;<br>
> + vd_printf("%s: %S updated path mode to (%lu, %lu - (%u x %u)",<br>
> __FUNCTION__,<br>
> + device_name,<br>
> + mode->sourceMode.position.x, mode->sourceMode.position.y,<br>
> + mode->sourceMode.width, mode->sourceMode.height);<br>
> + _path_state = PATH_UPDATED;<br>
> + return true;<br>
> +}<br>
> +<br>
> +void CCD::update_detached_primary_state(LPCTSTR device_name,<br>
> DISPLAYCONFIG_PATH_INFO * path_info)<br>
> +{<br>
> + DISPLAYCONFIG_MODE_INFO* mode(get_active_mode(device_name, false));<br>
> +<br>
> + //will need to reset monitor positions if primary detached<br>
> + path_info->flags = path_info->flags & ~DISPLAYCONFIG_PATH_ACTIVE;<br>
> + if (!mode|| mode->sourceMode.position.x != 0 ||<br>
> mode->sourceMode.position.y != 0) {<br>
> + return ;<br>
> + }<br>
> + _primary_detached = true;<br>
> +}<br>
> +<br>
> +bool CCD::set_path_state(LPCTSTR device_name, MONITOR_STATE new_state)<br>
> +{<br>
> + DISPLAYCONFIG_PATH_INFO* path(get_device_path(device_name, false));<br>
> + MONITOR_STATE current_path_state(MONITOR_DETACHED);<br>
> +<br>
> + if (path && (path->flags & DISPLAYCONFIG_PATH_ACTIVE)) {<br>
> + current_path_state = MONITOR_ATTACHED;<br>
> + }<br>
> +<br>
> + //If state didn't change, nothing to do<br>
> + if (current_path_state == new_state ) {<br>
> + return true;<br>
> + }<br>
> +<br>
> + if (!path) {<br>
> + return false;<br>
> + }<br>
> +<br>
> + _path_state = PATH_UPDATED;<br>
> + if (new_state == MONITOR_DETACHED) {<br>
> + update_detached_primary_state(device_name, path);<br>
> + } else {<br>
> + path->flags = path->flags | DISPLAYCONFIG_PATH_ACTIVE;<br>
> + set_display_config();<br>
> + }<br>
> + return true;<br>
> +}<br>
> +<br>
> +bool CCD::is_attached(LPCTSTR device_name)<br>
> +{<br>
> + DISPLAYCONFIG_PATH_INFO* path(get_device_path(device_name, false));<br>
> + if (!path) {<br>
> + return false;<br>
> + }<br>
> + return (path->flags & DISPLAYCONFIG_PATH_ACTIVE);<br>
> +}<br>
> +<br>
> +bool CCD::is_active_path(DISPLAYCONFIG_PATH_INFO * path)<br>
> +{<br>
> + if (!path || !(path->flags & DISPLAYCONFIG_PATH_ACTIVE) ||<br>
> + (path->sourceInfo.modeInfoIdx ==<br>
> DISPLAYCONFIG_PATH_MODE_IDX_INVALID)) {<br>
> + return false;<br>
> + }<br>
> + return true;<br>
> +}<br>
> diff --git a/vdagent/display_configuration.h<br>
> b/vdagent/display_configuration.h<br>
> new file mode 100755<br>
> index 0000000..870a28d<br>
> --- /dev/null<br>
> +++ b/vdagent/display_configuration.h<br>
> @@ -0,0 +1,191 @@<br>
> +/*<br>
> +Copyright (C) 2015 Red Hat, Inc.<br>
> +<br>
> +This program is free software; you can redistribute it and/or<br>
> +modify it under the terms of the GNU General Public License as<br>
> +published by the Free Software Foundation; either version 2 of<br>
> +the License, or (at your option) any later version.<br>
> +<br>
> +This program is distributed in the hope that it will be useful,<br>
> +but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
> +GNU General Public License for more details.<br>
> +<br>
> +You should have received a copy of the GNU General Public License<br>
> +along with this program. If not, see <<a href="http://www.gnu.org/licenses/" rel="noreferrer" target="_blank">http://www.gnu.org/licenses/</a>>.<br>
> +*/<br>
> +#ifndef _H_DISPLAY_CONFIGURATION<br>
> +#define _H_DISPLAY_CONFIGURATION<br>
> +<br>
> +#include <spice/qxl_windows.h><br>
> +#include <spice/qxl_dev.h><br>
> +#include "desktop_layout.h"<br>
> +#include "vdlog.h"<br>
> +<br>
> +enum DRIVER_TYPE {<br>
> + XPDM,<br>
> + WDDM,<br>
> + INVALID_DRIVER,<br>
> +};<br>
> +<br>
> +enum MONITOR_STATE {<br>
> + MONITOR_DETACHED,<br>
> + MONITOR_ATTACHED,<br>
> +};<br>
> +<br>
> +enum PATH_STATE {<br>
> + PATH_UPDATED,<br>
> + PATH_CURRENT,<br>
> +};<br>
> +<br>
> +enum DISPLAYCONFIG_TOPOLOGY_ID {};<br>
> +<br>
> +struct DISPLAYCONFIG_DEVICE_INFO_HEADER;<br>
> +struct DISPLAYCONFIG_MODE_INFO;<br>
> +struct DISPLAYCONFIG_PATH_INFO;<br>
> +<br>
> +//Makes calls into the CCD API for getting/setting display settings on WDDM<br>
> drivers<br>
> +//Use is exclusive to wddm display config class<br>
> +<br>
> +typedef LONG(APIENTRY*<br>
> PDISPLAYCONFIG_GETDEVICEINFO)(DISPLAYCONFIG_DEVICE_INFO_HEADER*);<br>
> +typedef LONG(APIENTRY* PGETDISPLAYCONFIG_BUFFERSIZES)(UINT32, UINT32*,<br>
> UINT32*);<br>
> +typedef LONG(APIENTRY* PQUERYDISPLAYCONFIG)(UINT32, UINT32*,<br>
> DISPLAYCONFIG_PATH_INFO*, UINT32*,<br>
> + DISPLAYCONFIG_MODE_INFO*,<br>
> DISPLAYCONFIG_TOPOLOGY_ID*);<br>
> +typedef LONG(APIENTRY* PSETDISPLAYCONFIG)(UINT32, DISPLAYCONFIG_PATH_INFO*,<br>
> UINT32,<br>
> + DISPLAYCONFIG_MODE_INFO*, UINT32);<br>
> +<br>
> +class CCD {<br>
> +protected:<br>
<br>
</div></div>This should be public, protected is used for inheritance.</blockquote><div>The class "WDDMInterface" has an instance of the "CCD" class, The constructor and destructor of the</div><div>"CCD" class are both protected, this enables the<b> friend </b>class "WDDMInterface" to</div><div>create and destroy CCD objects.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div><div class="h5"><span style="color:rgb(34,34,34)"> </span><br></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div><div class="h5">
> + CCD();<br>
> + ~CCD();<br>
> +<br>
> + bool query_display_config();<br>
> + bool set_display_config();<br>
> + bool update_mode_position(LPCTSTR device_name, DEVMODE* dev_mode);<br>
> + bool update_mode_size(LPCTSTR DeviceNmae, DEVMODE* dev_mode);<br>
> + void update_detached_primary_state(LPCTSTR device_name,<br>
> DISPLAYCONFIG_PATH_INFO * path_info);<br>
> + bool set_path_state(LPCTSTR device_name, MONITOR_STATE state);<br>
> + bool is_attached(LPCTSTR device_name);<br>
> + bool is_active_path(DISPLAYCONFIG_PATH_INFO * path);<br>
> + LONG error() { return _error; }<br>
> +<br>
> +private:<br>
> + bool load_api();<br>
> + bool get_config_buffers();<br>
> + void free_config_buffers();<br>
> + bool verify_primary_position();<br>
> + bool is_device_path(LPCTSTR device_name, DISPLAYCONFIG_PATH_INFO* path);<br>
> + DISPLAYCONFIG_MODE_INFO* get_active_mode(LPCTSTR device_name, bool<br>
> return_on_error);<br>
> + DISPLAYCONFIG_PATH_INFO* get_device_path(LPCTSTR device_name, bool<br>
> bActive);<br>
> + bool get_device_name_config(DISPLAYCONFIG_PATH_INFO* path, LPCTSTR<br>
> dev_name);<br>
> + void debug_print_config(const char* prefix = NULL);<br>
> +<br>
> +private:<br>
> + //CCD API stuff<br>
> + UINT32 _NumPathElements;<br>
> + UINT32 _NumModeElements;<br>
> + DISPLAYCONFIG_PATH_INFO* _pPathInfo;<br>
> + DISPLAYCONFIG_MODE_INFO* _pModeInfo;<br>
> +<br>
> + //CCD API function pointers<br>
> + PDISPLAYCONFIG_GETDEVICEINFO _pfnGetDeviceInfo;<br>
> + PGETDISPLAYCONFIG_BUFFERSIZES _pfnGetDisplayConfigBufferSizes;<br>
> + PQUERYDISPLAYCONFIG _pfnQueryDisplayConfig;<br>
> + PSETDISPLAYCONFIG _pfnSetDisplayConfig;<br>
> +<br>
> + LONG _error;<br>
> + bool _primary_detached;<br>
> + PATH_STATE _path_state;<br>
> + friend class WDDMInterface;<br>
<br>
</div></div>There should be no reason for friend.<br>
<span class=""><br>
> +};<br>
> +<br>
> +class DisplayMode;<br>
> +<br>
> +//Class provides interface to get/set display configurations<br>
> +class DisplayConfig {<br>
> +public:<br>
> + static DisplayConfig* create_config();<br>
> + DisplayConfig();;<br>
<br>
</span>typo (;;).<br>
<span class=""><br>
> + virtual ~DisplayConfig() {};<br>
> +<br>
> + virtual bool is_attached(DISPLAY_DEVICE* dev_info) = 0;<br>
> + virtual bool custom_display_escape(LPCTSTR device, DEVMODE* mode) = 0;<br>
> + virtual bool update_monitor_config(LPCTSTR device, DisplayMode* mode,<br>
> DEVMODE* dev_mode) = 0;<br>
> + virtual bool set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode,<br>
> MONITOR_STATE state) = 0;<br>
> + virtual LONG update_display_settings() = 0;<br>
> + virtual bool update_dev_mode_position(LPCTSTR dev_name, DEVMODE*<br>
> dev_mode, LONG x, LONG y) = 0;<br>
> + DRIVER_TYPE type() { return _driver_type; };<br>
<br>
</span>const and actually quite a bad design, I would remove this member<br>
entirely.<br>
<span class=""><br>
> + void set_monitors_config(bool flag) { _send_monitors_config = flag; }<br>
> + virtual void update_config_path() {};<br>
> +<br>
> +protected:<br>
> + DRIVER_TYPE _driver_type;<br>
<br>
</span>also I would remove this field. Would be much better to have a<br>
WDDMInterface::init that returns true/false.<br>
Actually WDDMInterface is quite a bad name for an implementation.<br>
<span class=""><br>
> + bool _send_monitors_config;<br>
> +};<br>
> +<br>
> +//DisplayConfig implementation for guest with XPDM graphics drivers<br>
> +class XPDMInterface : public DisplayConfig {<br>
> +public:<br>
> + XPDMInterface() :DisplayConfig() { _driver_type = XPDM; };<br>
> + ~XPDMInterface() {}<br>
> + bool is_attached(DISPLAY_DEVICE* dev_info);;<br>
<br>
</span>typo (;;).<br>
<div class=""><div class="h5"><br>
> + bool custom_display_escape(LPCTSTR device_name, DEVMODE* dev_mode);<br>
> + bool update_monitor_config(LPCTSTR device_name, DisplayMode* mode,<br>
> DEVMODE* dev_mode);<br>
> + bool set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode,<br>
> MONITOR_STATE state);<br>
> + LONG update_display_settings();<br>
> + bool update_dev_mode_position(LPCTSTR device_name, DEVMODE * dev_mode,<br>
> LONG x, LONG y);<br>
> +<br>
> +private:<br>
> + bool find_best_mode(LPCTSTR Device, DEVMODE* dev_mode);<br>
> +};<br>
> +<br>
> +//DisplayConfig implementation for guest with WDDM graphics drivers<br>
> +typedef UINT D3DKMT_HANDLE;<br>
> +<br>
> +struct D3DKMT_ESCAPE;<br>
> +struct D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME;<br>
> +struct D3DKMT_OPENADAPTERFROMDEVICENAME;<br>
> +struct D3DKMT_CLOSEADAPTER;<br>
> +struct D3DKMT_OPENADAPTERFROMHDC;<br>
> +<br>
> +typedef NTSTATUS(APIENTRY* PFND3DKMT_ESCAPE)(CONST D3DKMT_ESCAPE*);<br>
> +typedef NTSTATUS(APIENTRY*<br>
> PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME*);<br>
> +typedef NTSTATUS(APIENTRY*<br>
> PFND3DKMT_OPENADAPTERFROMDEVICENAME)(D3DKMT_OPENADAPTERFROMDEVICENAME*);<br>
> +typedef NTSTATUS(APIENTRY* PFND3DKMT_CLOSEADAPTER)(D3DKMT_CLOSEADAPTER*);<br>
> +typedef NTSTATUS(APIENTRY*<br>
> PFND3DKMT_OPENADAPTERFROMHDC)(D3DKMT_OPENADAPTERFROMHDC*);<br>
> +<br>
> +class WDDMInterface : public DisplayConfig {<br>
> +public:<br>
> + WDDMInterface();<br>
> + ~WDDMInterface();<br>
> + bool is_attached(DISPLAY_DEVICE* dev_info);<br>
> + bool set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode,<br>
> MONITOR_STATE state);<br>
> + LONG update_display_settings();<br>
> + bool custom_display_escape(LPCTSTR device_name, DEVMODE* dev_mode);<br>
> + bool update_monitor_config(LPCTSTR device_name, DisplayMode* mode,<br>
> DEVMODE* dev_mode);<br>
> + bool update_dev_mode_position(LPCTSTR device_name, DEVMODE * dev_mode,<br>
> LONG x, LONG y);<br>
> + void update_config_path();<br>
> +<br>
> +private:<br>
> + bool init_d3d_api();<br>
> + D3DKMT_HANDLE adapter_handle(LPCTSTR device_name);<br>
> + D3DKMT_HANDLE handle_from_DC(LPCTSTR adapter_name);<br>
> + D3DKMT_HANDLE handle_from_device_name(LPCTSTR adapter_name);<br>
> + D3DKMT_HANDLE handle_from_GDI_name(LPCTSTR adapter_name);<br>
> +<br>
> + void close_adapter(D3DKMT_HANDLE handle);<br>
> + bool escape(LPCTSTR device_name, void* data, UINT sizeData);<br>
> +<br>
> +private:<br>
> + //GDI Function pointers<br>
> + PFND3DKMT_OPENADAPTERFROMHDC _pfnOpen_adapter_hdc;<br>
> + PFND3DKMT_CLOSEADAPTER _pfnClose_adapter;<br>
> + PFND3DKMT_ESCAPE _pfnEscape;<br>
> + PFND3DKMT_OPENADAPTERFROMDEVICENAME _pfnOpen_adapter_device_name;<br>
> + PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME _pfnOpen_adapter_gdi_name;<br>
> +<br>
> + //object handles the CCD API<br>
> + CCD _ccd;<br>
> +};<br>
> +<br>
> +#endif<br>
> \ No newline at end of file<br>
> --<br>
> 2.5.5<br>
><br>
<br>
</div></div><span class=""><font color="#888888">Frediano<br>
</font></span></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><font size="4" color="#0b5394" face="times new roman, serif">Respectfully,<br></font><div style="font-size:12.8px;color:rgb(136,136,136)"><font size="4" color="#0b5394" face="times new roman, serif"><b><i>Sameeh Jubran</i></b></font></div><div style="font-size:12.8px;color:rgb(136,136,136)"><i style="color:rgb(7,55,99);font-family:"times new roman",serif;font-size:large"><span style="line-height:15px"><a href="https://il.linkedin.com/pub/sameeh-jubran/87/747/a8a" title="View public profile" name="UNIQUE_ID_SafeHtmlFilter_UNIQUE_ID_SafeHtmlFilter_UNIQUE_ID_SafeHtmlFilter_UNIQUE_ID_SafeHtmlFilter_14e2c1de96f8c195_UNIQUE_ID_SafeHtmlFilter_SafeHtmlFilter_SafeHtmlFilter_webProfileURL" style="color:rgb(17,85,204);margin:0px;padding:0px;border-width:0px;outline:none;vertical-align:baseline;text-decoration:none" target="_blank">Linkedin</a></span></i><br></div><div style="font-size:12.8px;color:rgb(136,136,136)"><font size="4" face="times new roman, serif" color="#073763"><i>Junior Software Engineer @ <a href="http://www.daynix.com" target="_blank">Daynix</a>.</i></font></div></div></div></div></div></div></div>
</div></div>