diff --git a/README.md b/README.md index 540ec7a2..11bce8f8 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,12 @@ Wine. All those differences are also documented on the Included bugfixes and improvements ================================== -**Bugfixes and features included in the next upcoming release [8]:** +**Bugfixes and features included in the next upcoming release [9]:** * Add partially support for sessionStorage * Anno 1602 installer depends on Windows 98 behavior of SHFileOperationW * FEAR 1 installer expects basic_string_wchar_dtor to return NULL ([Wine Bug #37358](http://bugs.winehq.org/show_bug.cgi?id=37358)) +* Multiple applications need EnumDisplayDevicesW implementation ([Wine Bug #34978](http://bugs.winehq.org/show_bug.cgi?id=34978)) * Support for D3DXGetShaderInputSemantics ([Wine Bug #22682](http://bugs.winehq.org/show_bug.cgi?id=22682)) * Support for ID3DXSkinInfoImpl_UpdateSkinnedMesh ([Wine Bug #32572](http://bugs.winehq.org/show_bug.cgi?id=32572)) * Support for UTF7 encoding/decoding ([Wine Bug #27388](http://bugs.winehq.org/show_bug.cgi?id=27388)) diff --git a/patches/Makefile b/patches/Makefile index d5adb73d..20e0d682 100644 --- a/patches/Makefile +++ b/patches/Makefile @@ -31,6 +31,7 @@ PATCHLIST := \ dbghelp-KdHelp.ok \ dsound-Fast_Mixer.ok \ fonts-Missing_Fonts.ok \ + gdi32-MultiMonitor.ok \ imm32-Cross_Thread_Access.ok \ iphlpapi-TCP_Table.ok \ kernel32-FindFirstFile.ok \ @@ -395,6 +396,26 @@ fonts-Missing_Fonts.ok: echo '+ { "fonts-Missing_Fonts", "Torsten Kurbad / Erich E. Hoover", "Implement missing fonts expected by Silverlight. [rev 2]" },'; \ ) > fonts-Missing_Fonts.ok +# Patchset gdi32-MultiMonitor +# | +# | Included patches: +# | * Add multi monitor support to gdi32. [by Ken Thomases] +# | +# | This patchset fixes the following Wine bugs: +# | * [#34978] Multiple applications need EnumDisplayDevicesW implementation +# | +# | Modified files: +# | * dlls/gdi32/driver.c, dlls/user32/misc.c, dlls/winex11.drv/xinerama.c +# | +.INTERMEDIATE: gdi32-MultiMonitor.ok +gdi32-MultiMonitor.ok: + $(call APPLY_FILE,gdi32-MultiMonitor/0001-gdi32-Also-accept-.-DISPLAY-n-devices-names-with-n-o.patch) + $(call APPLY_FILE,gdi32-MultiMonitor/0002-winex11-Make-GetMonitorInfo-give-a-different-device-.patch) + $(call APPLY_FILE,gdi32-MultiMonitor/0003-user32-Implement-EnumDisplayDevicesW-based-on-EnumDi.patch) + @( \ + echo '+ { "gdi32-MultiMonitor", "Ken Thomases", "Add multi monitor support to gdi32." },'; \ + ) > gdi32-MultiMonitor.ok + # Patchset imm32-Cross_Thread_Access # | # | Included patches: diff --git a/patches/gdi32-MultiMonitor/0001-gdi32-Also-accept-.-DISPLAY-n-devices-names-with-n-o.patch b/patches/gdi32-MultiMonitor/0001-gdi32-Also-accept-.-DISPLAY-n-devices-names-with-n-o.patch new file mode 100644 index 00000000..3d43201c --- /dev/null +++ b/patches/gdi32-MultiMonitor/0001-gdi32-Also-accept-.-DISPLAY-n-devices-names-with-n-o.patch @@ -0,0 +1,77 @@ +From b4797a84f8cb931433b055c55030b0eb86320789 Mon Sep 17 00:00:00 2001 +From: Ken Thomases +Date: Sat, 18 Oct 2014 22:25:25 +0200 +Subject: gdi32: Also accept "\\.\DISPLAY" devices names with other than + 1 as display devices. + +--- + dlls/gdi32/driver.c | 32 ++++++++++++++++++++++++++++---- + 1 file changed, 28 insertions(+), 4 deletions(-) + +diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c +index 4529562..9e4f6f4 100644 +--- a/dlls/gdi32/driver.c ++++ b/dlls/gdi32/driver.c +@@ -109,6 +109,32 @@ static const struct gdi_dc_funcs *get_display_driver(void) + + + /********************************************************************** ++ * is_display_device ++ */ ++static BOOL is_display_device( LPCWSTR name ) ++{ ++ static const WCHAR display_deviceW[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y'}; ++ const WCHAR *p = name; ++ ++ if (strncmpiW( name, display_deviceW, sizeof(display_deviceW) / sizeof(WCHAR) )) ++ return FALSE; ++ ++ p += sizeof(display_deviceW) / sizeof(WCHAR); ++ ++ if (!isdigitW( *p++ )) ++ return FALSE; ++ ++ for (; *p; p++) ++ { ++ if (!isdigitW( *p )) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++/********************************************************************** + * DRIVER_load_driver + */ + const struct gdi_dc_funcs *DRIVER_load_driver( LPCWSTR name ) +@@ -116,10 +142,9 @@ const struct gdi_dc_funcs *DRIVER_load_driver( LPCWSTR name ) + HMODULE module; + struct graphics_driver *driver, *new_driver; + static const WCHAR displayW[] = { 'd','i','s','p','l','a','y',0 }; +- static const WCHAR display1W[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0}; + + /* display driver is a special case */ +- if (!strcmpiW( name, displayW ) || !strcmpiW( name, display1W )) return get_display_driver(); ++ if (!strcmpiW( name, displayW ) || is_display_device( name )) return get_display_driver(); + + if ((module = GetModuleHandleW( name ))) + { +@@ -774,13 +799,12 @@ BOOL DRIVER_GetDriverName( LPCWSTR device, LPWSTR driver, DWORD size ) + { + static const WCHAR displayW[] = { 'd','i','s','p','l','a','y',0 }; + static const WCHAR devicesW[] = { 'd','e','v','i','c','e','s',0 }; +- static const WCHAR display1W[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0}; + static const WCHAR empty_strW[] = { 0 }; + WCHAR *p; + + /* display is a special case */ + if (!strcmpiW( device, displayW ) || +- !strcmpiW( device, display1W )) ++ is_display_device( device )) + { + lstrcpynW( driver, displayW, size ); + return TRUE; +-- +1.9.1 + diff --git a/patches/gdi32-MultiMonitor/0002-winex11-Make-GetMonitorInfo-give-a-different-device-.patch b/patches/gdi32-MultiMonitor/0002-winex11-Make-GetMonitorInfo-give-a-different-device-.patch new file mode 100644 index 00000000..838544cb --- /dev/null +++ b/patches/gdi32-MultiMonitor/0002-winex11-Make-GetMonitorInfo-give-a-different-device-.patch @@ -0,0 +1,60 @@ +From 67e34d580dc8ca1115c8e8b0d53cf7649c4c3dcf Mon Sep 17 00:00:00 2001 +From: Ken Thomases +Date: Sat, 18 Oct 2014 22:33:04 +0200 +Subject: winex11: Make GetMonitorInfo() give a different device name + (\.\DISPLAY) to each monitor + +--- + dlls/winex11.drv/xinerama.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c +index 7e28726..ace84c5 100644 +--- a/dlls/winex11.drv/xinerama.c ++++ b/dlls/winex11.drv/xinerama.c +@@ -30,6 +30,7 @@ + #include "wine/library.h" + #include "x11drv.h" + #include "wine/debug.h" ++#include "wine/unicode.h" + + WINE_DEFAULT_DEBUG_CHANNEL(x11drv); + +@@ -43,6 +44,7 @@ static MONITORINFOEXW default_monitor = + MONITORINFOF_PRIMARY, /* dwFlags */ + { '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 } /* szDevice */ + }; ++static const WCHAR monitor_deviceW[] = { '\\','\\','.','\\','D','I','S','P','L','A','Y','%','d',0 }; + + static MONITORINFOEXW *monitors; + static int nb_monitors; +@@ -127,6 +129,8 @@ static int query_screens(void) + if (monitors != &default_monitor) HeapFree( GetProcessHeap(), 0, monitors ); + if ((monitors = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*monitors) ))) + { ++ int device = 2; /* 1 is reserved for primary */ ++ + nb_monitors = count; + for (i = 0; i < nb_monitors; i++) + { +@@ -138,11 +142,15 @@ static int query_screens(void) + monitors[i].dwFlags = 0; + if (!IntersectRect( &monitors[i].rcWork, &rc_work, &monitors[i].rcMonitor )) + monitors[i].rcWork = monitors[i].rcMonitor; +- /* FIXME: using the same device name for all monitors for now */ +- lstrcpyW( monitors[i].szDevice, default_monitor.szDevice ); + } + + get_primary()->dwFlags |= MONITORINFOF_PRIMARY; ++ ++ for (i = 0; i < nb_monitors; i++) ++ { ++ snprintfW( monitors[i].szDevice, sizeof(monitors[i].szDevice) / sizeof(WCHAR), ++ monitor_deviceW, (monitors[i].dwFlags & MONITORINFOF_PRIMARY) ? 1 : device++ ); ++ } + } + else count = 0; + +-- +1.9.1 + diff --git a/patches/gdi32-MultiMonitor/0003-user32-Implement-EnumDisplayDevicesW-based-on-EnumDi.patch b/patches/gdi32-MultiMonitor/0003-user32-Implement-EnumDisplayDevicesW-based-on-EnumDi.patch new file mode 100644 index 00000000..85ab4834 --- /dev/null +++ b/patches/gdi32-MultiMonitor/0003-user32-Implement-EnumDisplayDevicesW-based-on-EnumDi.patch @@ -0,0 +1,138 @@ +From 5133a02b554cf4e9d10548be321bef52d25b4477 Mon Sep 17 00:00:00 2001 +From: Ken Thomases +Date: Sat, 18 Oct 2014 23:39:48 +0200 +Subject: user32: Implement EnumDisplayDevicesW() based on + EnumDisplayMonitors() and GetMonitorInfoW(). + +--- + dlls/user32/misc.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 84 insertions(+), 12 deletions(-) + +diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c +index 2e6cc35..b1d1bd8 100644 +--- a/dlls/user32/misc.c ++++ b/dlls/user32/misc.c +@@ -226,11 +226,74 @@ DWORD WINAPI SetLogonNotifyWindow(HWINSTA hwinsta,HWND hwnd) + return 1; + } + +-static const WCHAR primary_device_name[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0}; +-static const WCHAR primary_device_string[] = {'X','1','1',' ','W','i','n','d','o','w','i','n','g',' ', +- 'S','y','s','t','e','m',0}; +-static const WCHAR primary_device_deviceid[] = {'P','C','I','\\','V','E','N','_','0','0','0','0','&', ++static const WCHAR adapter_device_string[] = {'W','i','n','e',' ','D','i','s','p','l','a','y',' ', ++ 'A','d','a','p','t','e','r',0}; ++static const WCHAR adapter_device_deviceid[] = {'P','C','I','\\','V','E','N','_','0','0','0','0','&', + 'D','E','V','_','0','0','0','0',0}; ++static const WCHAR display_device_name[] = {'%','s','\\','M','o','n','i','t','o','r','0',0}; ++static const WCHAR display_device_string[] = {'W','i','n','e',' ','D','i','s','p','l','a','y',0}; ++static const WCHAR display_device_deviceid[] = {'M','O','N','I','T','O','R','\\','W','I','N','E','%','0','4','d',0}; ++ ++struct display_devices_enum_info ++{ ++ LPCWSTR adapter; ++ DWORD target; ++ DWORD non_primary_seen; ++ LPDISPLAY_DEVICEW device; ++}; ++ ++/*********************************************************************** ++ * display_devices_enum ++ * ++ * Helper callback for EnumDisplayDevicesW() ++ */ ++static BOOL CALLBACK display_devices_enum( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp ) ++{ ++ struct display_devices_enum_info *info = (struct display_devices_enum_info *)lp; ++ MONITORINFOEXW mon_info; ++ BOOL match; ++ ++ mon_info.cbSize = sizeof(mon_info); ++ GetMonitorInfoW( monitor, (MONITORINFO*)&mon_info ); ++ ++ if (!(mon_info.dwFlags & MONITORINFOF_PRIMARY)) ++ info->non_primary_seen++; ++ ++ if (info->adapter) ++ { ++ match = !strcmpiW( info->adapter, mon_info.szDevice ); ++ if (match) ++ { ++ snprintfW( info->device->DeviceName, sizeof(info->device->DeviceName) / sizeof(WCHAR), ++ display_device_name, mon_info.szDevice ); ++ lstrcpynW( info->device->DeviceString, display_device_string, sizeof(info->device->DeviceString) / sizeof(WCHAR) ); ++ ++ if (info->device->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->device->DeviceID)) ++ { ++ snprintfW( info->device->DeviceID, sizeof(info->device->DeviceID) / sizeof(WCHAR), ++ display_device_deviceid, (mon_info.dwFlags & MONITORINFOF_PRIMARY) ? 0 : info->non_primary_seen ); ++ } ++ } ++ } ++ else ++ { ++ if (mon_info.dwFlags & MONITORINFOF_PRIMARY) ++ match = (info->target == 0); ++ else ++ match = (info->target == info->non_primary_seen); ++ ++ if (match) ++ { ++ lstrcpynW( info->device->DeviceName, mon_info.szDevice, sizeof(info->device->DeviceName) / sizeof(WCHAR) ); ++ lstrcpynW( info->device->DeviceString, adapter_device_string, sizeof(info->device->DeviceString) / sizeof(WCHAR) ); ++ ++ if (info->device->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->device->DeviceID)) ++ lstrcpynW( info->device->DeviceID, adapter_device_deviceid, sizeof(info->device->DeviceID) / sizeof(WCHAR) ); ++ } ++ } ++ ++ return !match; ++} + + /*********************************************************************** + * EnumDisplayDevicesA (USER32.@) +@@ -271,24 +334,33 @@ BOOL WINAPI EnumDisplayDevicesA( LPCSTR lpDevice, DWORD i, LPDISPLAY_DEVICEA lpD + BOOL WINAPI EnumDisplayDevicesW( LPCWSTR lpDevice, DWORD i, LPDISPLAY_DEVICEW lpDisplayDevice, + DWORD dwFlags ) + { +- FIXME("(%s,%d,%p,0x%08x), stub!\n",debugstr_w(lpDevice),i,lpDisplayDevice,dwFlags); ++ struct display_devices_enum_info info; + +- if (i) ++ TRACE("(%s,%d,%p,0x%08x)\n",debugstr_w(lpDevice),i,lpDisplayDevice,dwFlags); ++ ++ if (lpDevice && i) + return FALSE; + +- memcpy(lpDisplayDevice->DeviceName, primary_device_name, sizeof(primary_device_name)); +- memcpy(lpDisplayDevice->DeviceString, primary_device_string, sizeof(primary_device_string)); +- + lpDisplayDevice->StateFlags = + DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | +- DISPLAY_DEVICE_PRIMARY_DEVICE | + DISPLAY_DEVICE_VGA_COMPATIBLE; + +- if(lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(lpDisplayDevice->DeviceID)) +- memcpy(lpDisplayDevice->DeviceID, primary_device_deviceid, sizeof(primary_device_deviceid)); ++ if (!lpDevice && i == 0) ++ lpDisplayDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE; ++ ++ info.adapter = lpDevice; ++ info.target = i; ++ info.non_primary_seen = 0; ++ info.device = lpDisplayDevice; ++ if (EnumDisplayMonitors( 0, NULL, display_devices_enum, (LPARAM)&info )) ++ return FALSE; ++ + if(lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(lpDisplayDevice->DeviceKey)) + lpDisplayDevice->DeviceKey[0] = 0; + ++ TRACE("DeviceName %s DeviceString %s DeviceID %s DeviceKey %s\n", debugstr_w(lpDisplayDevice->DeviceName), ++ debugstr_w(lpDisplayDevice->DeviceString), debugstr_w(lpDisplayDevice->DeviceID), debugstr_w(lpDisplayDevice->DeviceKey)); ++ + return TRUE; + } + +-- +1.9.1 + diff --git a/patches/gdi32-MultiMonitor/definition b/patches/gdi32-MultiMonitor/definition new file mode 100644 index 00000000..86fd7b0b --- /dev/null +++ b/patches/gdi32-MultiMonitor/definition @@ -0,0 +1,4 @@ +Author: Ken Thomases +Subject: Add multi monitor support to gdi32. +Revision: 1 +Fixes: [34978] Multiple applications need EnumDisplayDevicesW implementation