Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/winemac.drv/cocoa_display.m | 108 +++++++++++++++++++++++++++++++++++++++ dlls/winemac.drv/display.c | 103 +++++++++++++++++++++++++++++++++++-- dlls/winemac.drv/macdrv_cocoa.h | 14 +++++ dlls/winemac.drv/macdrv_main.c | 2 + 4 files changed, 222 insertions(+), 5 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m index 53b1fb0a68..e1c1b0cb17 100644 --- a/dlls/winemac.drv/cocoa_display.m +++ b/dlls/winemac.drv/cocoa_display.m @@ -582,3 +582,111 @@ void macdrv_free_adapters(struct macdrv_adapter* adapters) if (adapters) free(adapters); } + +/*********************************************************************** + * macdrv_get_monitors + * + * Get a list of monitors under adapter_id. The first monitor is primary if adapter is primary. + * Call macdrv_free_monitors() when you are done using the data. + * + * Returns non-zero value on failure with parameters unchanged and zero on success. + */ +int macdrv_get_monitors(uint32_t adapter_id, struct macdrv_monitor** new_monitors, int* count) +{ + struct macdrv_monitor* monitors = NULL; + struct macdrv_monitor* realloc_monitors; + struct macdrv_display* displays = NULL; + CGDirectDisplayID display_ids[16]; + uint32_t display_id_count; + int primary_index = 0; + int monitor_count = 0; + int display_count; + int capacity; + int ret = -1; + int i, j; + + /* 2 should be enough for most cases */ + capacity = 2; + monitors = calloc(capacity, sizeof(*monitors)); + if (!monitors) + return -1; + + /* Report an inactive monitor */ + if (!CGDisplayIsActive(adapter_id) && !CGDisplayIsInMirrorSet(adapter_id)) + { + strcpy(monitors[monitor_count].name, "Generic Non-PnP Monitor"); + monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED; + monitor_count++; + } + /* Report active and mirrored monitors in the same mirroring set */ + else + { + if (CGGetOnlineDisplayList(sizeof(display_ids) / sizeof(display_ids[0]), display_ids, &display_id_count) + != kCGErrorSuccess) + goto done; + + if (macdrv_get_displays(&displays, &display_count)) + goto done; + + for (i = 0; i < display_id_count; i++) + { + if (display_ids[i] != adapter_id && CGDisplayMirrorsDisplay(display_ids[i]) != adapter_id) + continue; + + /* Find and fill in monitor info */ + for (j = 0; j < display_count; j++) + { + if (displays[i].displayID == display_ids[j] + || CGDisplayMirrorsDisplay(display_ids[i]) == displays[j].displayID) + { + /* Allocate more space if needed */ + if (monitor_count >= capacity) + { + capacity *= 2; + realloc_monitors = realloc(monitors, sizeof(*monitors) * capacity); + if (!realloc_monitors) + goto done; + monitors = realloc_monitors; + } + + if (CGDisplayIsMain(display_ids[j])) + primary_index = monitor_count; + + strcpy(monitors[monitor_count].name, "Generic Non-PnP Monitor"); + monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE; + monitor_count++; + } + } + } + + /* Make sure the first monitor on primary adapter is primary */ + if (primary_index) + { + struct macdrv_monitor tmp; + tmp = monitors[0]; + monitors[0] = monitors[primary_index]; + monitors[primary_index] = tmp; + } + } + + *new_monitors = monitors; + *count = monitor_count; + ret = 0; +done: + if (displays) + macdrv_free_displays(displays); + if (ret) + macdrv_free_monitors(monitors); + return ret; +} + +/*********************************************************************** + * macdrv_free_monitors + * + * Frees an monitor list allocated from macdrv_get_monitors() + */ +void macdrv_free_monitors(struct macdrv_monitor* monitors) +{ + if (monitors) + free(monitors); +} diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c index 6b2eea9ecc..fdb2415885 100644 --- a/dlls/winemac.drv/display.c +++ b/dlls/winemac.drv/display.c @@ -51,14 +51,18 @@ struct display_mode_descriptor
BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW devmode, DWORD flags);
+/* Wine specific monitor properties */ +DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
static const char initial_mode_key[] = "Initial Display Mode"; static const WCHAR pixelencodingW[] = {'P','i','x','e','l','E','n','c','o','d','i','n','g',0}; static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0}; +static const WCHAR displayW[] = {'D','I','S','P','L','A','Y',0}; static const WCHAR pciW[] = {'P','C','I',0}; static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0}; static const WCHAR symbolic_link_valueW[]= {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0}; static const WCHAR gpu_idW[] = {'G','P','U','I','D',0}; +static const WCHAR mointor_id_fmtW[] = {'M','o','n','i','t','o','r','I','D','%','d',0}; static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0}; static const WCHAR guid_fmtW[] = { '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0','2','x','%','0','2','x','-', @@ -100,6 +104,13 @@ static const WCHAR nt_classW[] = { 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\', 'C','o','n','t','r','o','l','\', 'C','l','a','s','s','\',0}; +static const WCHAR monitor_instance_fmtW[] = { + 'D','I','S','P','L','A','Y','\', + 'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r','\', + '%','0','4','X','&','%','0','4','X',0}; +static const WCHAR monitor_hardware_idW[] = { + 'M','O','N','I','T','O','R','\', + 'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0};
static CFArrayRef modes; @@ -1538,7 +1549,7 @@ done: * * Return FALSE on failure and TRUE on success. */ -static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index, int adapter_index, +static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index, int adapter_index, int monitor_count, const struct macdrv_gpu *gpu, const WCHAR *guid_string, const WCHAR *gpu_driver, const struct macdrv_adapter *adapter) { @@ -1548,6 +1559,7 @@ static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index, HKEY hkey = NULL; BOOL ret = FALSE; LSTATUS ls; + INT i;
sprintfW(key_nameW, device_video_fmtW, video_index); lstrcpyW(bufferW, machine_prefixW); @@ -1582,6 +1594,15 @@ static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index, if (RegSetValueExW(hkey, gpu_idW, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR))) goto done;
+ /* Write all monitor instances paths under this adapter */ + for (i = 0; i < monitor_count; i++) + { + sprintfW(key_nameW, mointor_id_fmtW, i); + sprintfW(bufferW, monitor_instance_fmtW, video_index, i); + if (RegSetValueExW(hkey, key_nameW, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR))) + goto done; + } + /* Write StateFlags */ if (RegSetValueExW(hkey, state_flagsW, 0, REG_DWORD, (const BYTE *)&adapter->state_flags, sizeof(adapter->state_flags))) @@ -1595,6 +1616,52 @@ done: return ret; }
+/*********************************************************************** + * macdrv_init_monitor + * + * Initialize an monitor. + * + * Return FALSE on failure and TRUE on success. + */ +static BOOL macdrv_init_monitor(HDEVINFO devinfo, const struct macdrv_monitor *monitor, int monitor_index, + int video_index) +{ + SP_DEVINFO_DATA device_data = {sizeof(SP_DEVINFO_DATA)}; + WCHAR nameW[MAX_PATH]; + WCHAR bufferW[MAX_PATH]; + HKEY hkey; + BOOL ret = FALSE; + + /* Create GUID_DEVCLASS_MONITOR instance */ + sprintfW(bufferW, monitor_instance_fmtW, video_index, monitor_index); + MultiByteToWideChar(CP_UTF8, 0, monitor->name, -1, nameW, ARRAY_SIZE(nameW)); + SetupDiCreateDeviceInfoW(devinfo, bufferW, &GUID_DEVCLASS_MONITOR, nameW, NULL, 0, &device_data); + if (!SetupDiRegisterDeviceInfo(devinfo, &device_data, 0, NULL, NULL, NULL)) + goto done; + + /* Write HardwareID registry property */ + if (!SetupDiSetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_HARDWAREID, + (const BYTE *)monitor_hardware_idW, sizeof(monitor_hardware_idW))) + goto done; + + /* Create driver key */ + hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL); + RegCloseKey(hkey); + + /* FIXME: + * Following properties are Wine specific, see comments in macdrv_init_adapter for details */ + /* StateFlags */ + if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, DEVPROP_TYPE_UINT32, + (const BYTE *)&monitor->state_flags, sizeof(monitor->state_flags), 0)) + goto done; + + ret = TRUE; +done: + if (!ret) + ERR("Failed to initialize monitor\n"); + return ret; +} + static void prepare_devices(HKEY video_hkey) { static const BOOL not_present = FALSE; @@ -1602,6 +1669,15 @@ static void prepare_devices(HKEY video_hkey) HDEVINFO devinfo; DWORD i = 0;
+ /* Remove all monitors */ + devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, displayW, NULL, 0); + while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data)) + { + if (!SetupDiRemoveDevice(devinfo, &device_data)) + ERR("Failed to remove monitor\n"); + } + SetupDiDestroyDeviceInfoList(devinfo); + /* Clean up old adapter keys for reinitialization */ RegDeleteTreeW(video_hkey, NULL);
@@ -1610,6 +1686,7 @@ static void prepare_devices(HKEY video_hkey) * case application uses SetupDiGetClassDevsW to enumerate devices. Wrong devices could exist in registry as a result * of prefix copying or having devices unplugged. But then we couldn't simply delete GPUs because we need to retain * the same GUID for the same GPU. */ + i = 0; devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, pciW, NULL, 0); while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data)) { @@ -1651,9 +1728,10 @@ void macdrv_init_display_devices(void) HANDLE mutex; struct macdrv_gpu *gpus = NULL; struct macdrv_adapter *adapters = NULL; - INT gpu_count, adapter_count; - INT gpu, adapter; - HDEVINFO gpu_devinfo = NULL; + struct macdrv_monitor *monitors = NULL; + INT gpu_count, adapter_count, monitor_count; + INT gpu, adapter, monitor; + HDEVINFO gpu_devinfo = NULL, monitor_devinfo = NULL; HKEY video_hkey = NULL; INT video_index = 0; DWORD disposition = 0; @@ -1679,6 +1757,7 @@ void macdrv_init_display_devices(void) prepare_devices(video_hkey);
gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL); + monitor_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR, NULL);
/* Initialize GPUs */ if (macdrv_get_gpus(&gpus, &gpu_count)) @@ -1695,10 +1774,22 @@ void macdrv_init_display_devices(void)
for (adapter = 0; adapter < adapter_count; adapter++) { - if (!macdrv_init_adapter(video_hkey, video_index, gpu, adapter, &gpus[gpu], guidW, driverW, + if (macdrv_get_monitors(adapters[adapter].id, &monitors, &monitor_count)) + goto done; + + if (!macdrv_init_adapter(video_hkey, video_index, gpu, adapter, monitor_count, &gpus[gpu], guidW, driverW, &adapters[adapter])) goto done;
+ /* Initialize monitors */ + for (monitor = 0; monitor < monitor_count; monitor++) + { + if (!macdrv_init_monitor(monitor_devinfo, &monitors[monitor], monitor, video_index)) + goto done; + } + + macdrv_free_monitors(monitors); + monitors = NULL; video_index++; }
@@ -1708,6 +1799,7 @@ void macdrv_init_display_devices(void)
done: cleanup_devices(); + SetupDiDestroyDeviceInfoList(monitor_devinfo); SetupDiDestroyDeviceInfoList(gpu_devinfo); RegCloseKey(video_hkey);
@@ -1716,4 +1808,5 @@ done:
macdrv_free_gpus(gpus); macdrv_free_adapters(adapters); + macdrv_free_monitors(monitors); } diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index b960e902e3..96ebb97e76 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -261,6 +261,9 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point) /* Used DISPLAY_DEVICE.StateFlags for adapters */ #define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 #define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 +/* Used DISPLAY_DEVICE.StateFlags for monitors */ +#define DISPLAY_DEVICE_ACTIVE 0x00000001 +#define DISPLAY_DEVICE_ATTACHED 0x00000002
/* Represent a physical GPU in the PCI slots */ struct macdrv_gpu @@ -285,6 +288,15 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point) uint32_t state_flags; };
+/* Represent a monitor in EnumDisplayDevices context */ +struct macdrv_monitor +{ + /* Name, in UTF-8 encoding */ + char name[128]; + /* StateFlags in DISPLAY_DEVICE struct */ + uint32_t state_flags; +}; + extern int macdrv_get_displays(struct macdrv_display** displays, int* count) DECLSPEC_HIDDEN; extern void macdrv_free_displays(struct macdrv_display* displays) DECLSPEC_HIDDEN; extern int macdrv_set_display_mode(const struct macdrv_display* display, @@ -293,6 +305,8 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display, extern void macdrv_free_gpus(struct macdrv_gpu* gpus) DECLSPEC_HIDDEN; extern int macdrv_get_adapters(uint64_t gpu_id, struct macdrv_adapter** adapters, int* count) DECLSPEC_HIDDEN; extern void macdrv_free_adapters(struct macdrv_adapter* adapters) DECLSPEC_HIDDEN; +extern int macdrv_get_monitors(uint32_t adapter_id, struct macdrv_monitor** monitors, int* count) DECLSPEC_HIDDEN; +extern void macdrv_free_monitors(struct macdrv_monitor* monitors) DECLSPEC_HIDDEN;
/* event */ diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index 544d448f9f..038578491f 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -299,6 +299,8 @@ static BOOL process_attach(void) return FALSE; }
+ macdrv_init_display_devices(); + return TRUE; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=54470
Your paranoid android.
=== debian9 (64 bit WoW report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000