winemac: Implement ChangeDisplaySettingsEx().
[wine] / dlls / winemac.drv / display.c
1 /*
2  * MACDRV display settings
3  *
4  * Copyright 2003 Alexander James Pasadyn
5  * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include "macdrv.h"
25 #include "winuser.h"
26 #include "winreg.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(display);
29
30
31 BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW devmode, DWORD flags);
32
33
34 static CFArrayRef modes;
35 static int default_mode_bpp;
36 static CRITICAL_SECTION modes_section;
37 static CRITICAL_SECTION_DEBUG critsect_debug =
38 {
39     0, 0, &modes_section,
40     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
41       0, 0, { (DWORD_PTR)(__FILE__ ": modes_section") }
42 };
43 static CRITICAL_SECTION modes_section = { &critsect_debug, -1, 0, 0, 0, 0 };
44
45
46 static inline HMONITOR display_id_to_monitor(CGDirectDisplayID display_id)
47 {
48     return (HMONITOR)(UINT_PTR)display_id;
49 }
50
51 static inline CGDirectDisplayID monitor_to_display_id(HMONITOR handle)
52 {
53     return (CGDirectDisplayID)(UINT_PTR)handle;
54 }
55
56
57 static BOOL get_display_device_reg_key(char *key, unsigned len)
58 {
59     static const char display_device_guid_prop[] = "__wine_display_device_guid";
60     static const char video_path[] = "System\\CurrentControlSet\\Control\\Video\\{";
61     static const char display0[] = "}\\0000";
62     ATOM guid_atom;
63
64     assert(len >= sizeof(video_path) + sizeof(display0) + 40);
65
66     guid_atom = HandleToULong(GetPropA(GetDesktopWindow(), display_device_guid_prop));
67     if (!guid_atom) return FALSE;
68
69     memcpy(key, video_path, sizeof(video_path));
70
71     if (!GlobalGetAtomNameA(guid_atom, key + strlen(key), 40))
72         return FALSE;
73
74     strcat(key, display0);
75
76     TRACE("display device key %s\n", wine_dbgstr_a(key));
77     return TRUE;
78 }
79
80
81 static BOOL read_registry_settings(DEVMODEW *dm)
82 {
83     char wine_mac_reg_key[128];
84     HKEY hkey;
85     DWORD type, size;
86     BOOL ret = TRUE;
87
88     dm->dmFields = 0;
89
90     if (!get_display_device_reg_key(wine_mac_reg_key, sizeof(wine_mac_reg_key)))
91         return FALSE;
92
93     if (RegOpenKeyExA(HKEY_CURRENT_CONFIG, wine_mac_reg_key, 0, KEY_READ, &hkey))
94         return FALSE;
95
96 #define query_value(name, data) \
97     size = sizeof(DWORD); \
98     if (RegQueryValueExA(hkey, name, 0, &type, (LPBYTE)(data), &size) || \
99         type != REG_DWORD || size != sizeof(DWORD)) \
100         ret = FALSE
101
102     query_value("DefaultSettings.BitsPerPel", &dm->dmBitsPerPel);
103     dm->dmFields |= DM_BITSPERPEL;
104     query_value("DefaultSettings.XResolution", &dm->dmPelsWidth);
105     dm->dmFields |= DM_PELSWIDTH;
106     query_value("DefaultSettings.YResolution", &dm->dmPelsHeight);
107     dm->dmFields |= DM_PELSHEIGHT;
108     query_value("DefaultSettings.VRefresh", &dm->dmDisplayFrequency);
109     dm->dmFields |= DM_DISPLAYFREQUENCY;
110     query_value("DefaultSettings.Flags", &dm->dmDisplayFlags);
111     dm->dmFields |= DM_DISPLAYFLAGS;
112     query_value("DefaultSettings.XPanning", &dm->dmPosition.x);
113     query_value("DefaultSettings.YPanning", &dm->dmPosition.y);
114     query_value("DefaultSettings.Orientation", &dm->dmDisplayOrientation);
115     query_value("DefaultSettings.FixedOutput", &dm->dmDisplayFixedOutput);
116
117 #undef query_value
118
119     RegCloseKey(hkey);
120     return ret;
121 }
122
123
124 static BOOL write_registry_settings(const DEVMODEW *dm)
125 {
126     char wine_mac_reg_key[128];
127     HKEY hkey;
128     BOOL ret = TRUE;
129
130     if (!get_display_device_reg_key(wine_mac_reg_key, sizeof(wine_mac_reg_key)))
131         return FALSE;
132
133     if (RegCreateKeyExA(HKEY_CURRENT_CONFIG, wine_mac_reg_key, 0, NULL,
134                         REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, NULL))
135         return FALSE;
136
137 #define set_value(name, data) \
138     if (RegSetValueExA(hkey, name, 0, REG_DWORD, (const BYTE*)(data), sizeof(DWORD))) \
139         ret = FALSE
140
141     set_value("DefaultSettings.BitsPerPel", &dm->dmBitsPerPel);
142     set_value("DefaultSettings.XResolution", &dm->dmPelsWidth);
143     set_value("DefaultSettings.YResolution", &dm->dmPelsHeight);
144     set_value("DefaultSettings.VRefresh", &dm->dmDisplayFrequency);
145     set_value("DefaultSettings.Flags", &dm->dmDisplayFlags);
146     set_value("DefaultSettings.XPanning", &dm->dmPosition.x);
147     set_value("DefaultSettings.YPanning", &dm->dmPosition.y);
148     set_value("DefaultSettings.Orientation", &dm->dmDisplayOrientation);
149     set_value("DefaultSettings.FixedOutput", &dm->dmDisplayFixedOutput);
150
151 #undef set_value
152
153     RegCloseKey(hkey);
154     return ret;
155 }
156
157
158 static int display_mode_bits_per_pixel(CGDisplayModeRef display_mode)
159 {
160     CFStringRef pixel_encoding;
161     int bits_per_pixel = 0;
162
163     pixel_encoding = CGDisplayModeCopyPixelEncoding(display_mode);
164     if (pixel_encoding)
165     {
166         if (CFEqual(pixel_encoding, CFSTR(kIO32BitFloatPixels)))
167             bits_per_pixel = 128;
168         else if (CFEqual(pixel_encoding, CFSTR(kIO16BitFloatPixels)))
169             bits_per_pixel = 64;
170         else if (CFEqual(pixel_encoding, CFSTR(kIO64BitDirectPixels)))
171             bits_per_pixel = 64;
172         else if (CFEqual(pixel_encoding, CFSTR(kIO30BitDirectPixels)))
173             bits_per_pixel = 30;
174         else if (CFEqual(pixel_encoding, CFSTR(IO32BitDirectPixels)))
175             bits_per_pixel = 32;
176         else if (CFEqual(pixel_encoding, CFSTR(IO16BitDirectPixels)))
177             bits_per_pixel = 16;
178         else if (CFEqual(pixel_encoding, CFSTR(IO8BitIndexedPixels)))
179             bits_per_pixel = 8;
180         else if (CFEqual(pixel_encoding, CFSTR(IO4BitIndexedPixels)))
181             bits_per_pixel = 4;
182         else if (CFEqual(pixel_encoding, CFSTR(IO2BitIndexedPixels)))
183             bits_per_pixel = 2;
184         else if (CFEqual(pixel_encoding, CFSTR(IO1BitIndexedPixels)))
185             bits_per_pixel = 1;
186
187         CFRelease(pixel_encoding);
188     }
189
190     return bits_per_pixel;
191 }
192
193
194 static int get_default_bpp(void)
195 {
196     int ret;
197
198     EnterCriticalSection(&modes_section);
199
200     if (!default_mode_bpp)
201     {
202         CGDisplayModeRef mode = CGDisplayCopyDisplayMode(kCGDirectMainDisplay);
203         if (mode)
204         {
205             default_mode_bpp = display_mode_bits_per_pixel(mode);
206             CFRelease(mode);
207         }
208
209         if (!default_mode_bpp)
210             default_mode_bpp = 32;
211     }
212
213     ret = default_mode_bpp;
214
215     LeaveCriticalSection(&modes_section);
216
217     TRACE(" -> %d\n", ret);
218     return ret;
219 }
220
221
222 /***********************************************************************
223  *              ChangeDisplaySettingsEx  (MACDRV.@)
224  *
225  */
226 LONG CDECL macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
227                                           HWND hwnd, DWORD flags, LPVOID lpvoid)
228 {
229     LONG ret = DISP_CHANGE_BADMODE;
230     int bpp;
231     DEVMODEW dm;
232     BOOL def_mode = TRUE;
233     struct macdrv_display *displays;
234     int num_displays;
235     CFArrayRef display_modes;
236     CFIndex count, i, safe;
237
238     TRACE("%s %p %p 0x%08x %p\n", debugstr_w(devname), devmode, hwnd, flags, lpvoid);
239
240     if (devmode)
241     {
242         /* this is the minimal dmSize that XP accepts */
243         if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmFields))
244             return DISP_CHANGE_FAILED;
245
246         if (devmode->dmSize >= FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(devmode->dmFields))
247         {
248             if (((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
249                 ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
250                 ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
251                 ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
252                 def_mode = FALSE;
253         }
254     }
255
256     if (def_mode)
257     {
258         if (!macdrv_EnumDisplaySettingsEx(devname, ENUM_REGISTRY_SETTINGS, &dm, 0))
259         {
260             ERR("Default mode not found!\n");
261             return DISP_CHANGE_BADMODE;
262         }
263
264         TRACE("Return to original display mode\n");
265         devmode = &dm;
266     }
267
268     if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
269     {
270         WARN("devmode doesn't specify the resolution: %04x\n", devmode->dmFields);
271         return DISP_CHANGE_BADMODE;
272     }
273
274     if (macdrv_get_displays(&displays, &num_displays))
275         return DISP_CHANGE_FAILED;
276
277     display_modes = CGDisplayCopyAllDisplayModes(displays[0].displayID, NULL);
278     if (!display_modes)
279     {
280         macdrv_free_displays(displays);
281         return DISP_CHANGE_FAILED;
282     }
283
284     bpp = get_default_bpp();
285     if ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel != bpp)
286         TRACE("using default %d bpp instead of caller's request %d bpp\n", bpp, devmode->dmBitsPerPel);
287
288     TRACE("looking for %dx%dx%dbpp @%d Hz",
289           (devmode->dmFields & DM_PELSWIDTH ? devmode->dmPelsWidth : 0),
290           (devmode->dmFields & DM_PELSHEIGHT ? devmode->dmPelsHeight : 0),
291           bpp,
292           (devmode->dmFields & DM_DISPLAYFREQUENCY ? devmode->dmDisplayFrequency : 0));
293     if (devmode->dmFields & DM_DISPLAYFIXEDOUTPUT)
294         TRACE(" %sstretched", devmode->dmDisplayFixedOutput == DMDFO_STRETCH ? "" : "un");
295     if (devmode->dmFields & DM_DISPLAYFLAGS)
296         TRACE(" %sinterlaced", devmode->dmDisplayFlags & DM_INTERLACED ? "" : "non-");
297     TRACE("\n");
298
299     safe = -1;
300     count = CFArrayGetCount(display_modes);
301     for (i = 0; i < count; i++)
302     {
303         CGDisplayModeRef display_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(display_modes, i);
304         uint32_t io_flags = CGDisplayModeGetIOFlags(display_mode);
305         int mode_bpp = display_mode_bits_per_pixel(display_mode);
306         size_t width = CGDisplayModeGetWidth(display_mode);
307         size_t height = CGDisplayModeGetHeight(display_mode);
308
309         if (!(io_flags & kDisplayModeValidFlag) || !(io_flags & kDisplayModeSafeFlag))
310             continue;
311
312         safe++;
313
314         if (bpp != mode_bpp)
315             continue;
316
317         if (devmode->dmFields & DM_PELSWIDTH)
318         {
319             if (devmode->dmPelsWidth != width)
320                 continue;
321         }
322         if (devmode->dmFields & DM_PELSHEIGHT)
323         {
324             if (devmode->dmPelsHeight != height)
325                 continue;
326         }
327         if ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency != 0)
328         {
329             double refresh_rate = CGDisplayModeGetRefreshRate(display_mode);
330             if (!refresh_rate)
331                 refresh_rate = 60;
332             if (devmode->dmDisplayFrequency != (DWORD)refresh_rate)
333                 continue;
334         }
335         if (devmode->dmFields & DM_DISPLAYFIXEDOUTPUT)
336         {
337             if (!(devmode->dmDisplayFixedOutput == DMDFO_STRETCH) != !(io_flags & kDisplayModeStretchedFlag))
338                 continue;
339         }
340         if (devmode->dmFields & DM_DISPLAYFLAGS)
341         {
342             if (!(devmode->dmDisplayFlags & DM_INTERLACED) != !(io_flags & kDisplayModeInterlacedFlag))
343                 continue;
344         }
345
346         /* we have a valid mode */
347         TRACE("Requested display settings match mode %ld\n", safe);
348
349         if ((flags & CDS_UPDATEREGISTRY) && !write_registry_settings(devmode))
350         {
351             WARN("Failed to update registry\n");
352             ret = DISP_CHANGE_NOTUPDATED;
353             break;
354         }
355
356         if (flags & (CDS_TEST | CDS_NORESET))
357             ret = DISP_CHANGE_SUCCESSFUL;
358         else
359         {
360             if (macdrv_set_display_mode(&displays[0], display_mode))
361             {
362                 SendMessageW(GetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
363                              MAKELPARAM(width, height));
364                 ret = DISP_CHANGE_SUCCESSFUL;
365             }
366             else
367             {
368                 WARN("Failed to set display mode\n");
369                 ret = DISP_CHANGE_FAILED;
370             }
371         }
372
373         break;
374     }
375
376     CFRelease(display_modes);
377     macdrv_free_displays(displays);
378
379     if (i >= count)
380     {
381         /* no valid modes found */
382         ERR("No matching mode found %ux%ux%d @%u!\n", devmode->dmPelsWidth, devmode->dmPelsHeight,
383             bpp, devmode->dmDisplayFrequency);
384     }
385
386     return ret;
387 }
388
389
390 /***********************************************************************
391  *              EnumDisplayMonitors  (MACDRV.@)
392  */
393 BOOL CDECL macdrv_EnumDisplayMonitors(HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lparam)
394 {
395     struct macdrv_display *displays;
396     int num_displays;
397     int i;
398     BOOL ret = TRUE;
399
400     TRACE("%p, %s, %p, %#lx\n", hdc, wine_dbgstr_rect(rect), proc, lparam);
401
402     if (hdc)
403     {
404         POINT origin;
405         RECT limit;
406
407         if (!GetDCOrgEx(hdc, &origin)) return FALSE;
408         if (GetClipBox(hdc, &limit) == ERROR) return FALSE;
409
410         if (rect && !IntersectRect(&limit, &limit, rect)) return TRUE;
411
412         if (macdrv_get_displays(&displays, &num_displays))
413             return FALSE;
414
415         for (i = 0; i < num_displays; i++)
416         {
417             RECT monrect = rect_from_cgrect(displays[i].frame);
418             OffsetRect(&monrect, -origin.x, -origin.y);
419             if (IntersectRect(&monrect, &monrect, &limit))
420             {
421                 HMONITOR monitor = display_id_to_monitor(displays[i].displayID);
422                 TRACE("monitor %d handle %p @ %s\n", i, monitor, wine_dbgstr_rect(&monrect));
423                 if (!proc(monitor, hdc, &monrect, lparam))
424                 {
425                     ret = FALSE;
426                     break;
427                 }
428             }
429         }
430     }
431     else
432     {
433         if (macdrv_get_displays(&displays, &num_displays))
434             return FALSE;
435
436         for (i = 0; i < num_displays; i++)
437         {
438             RECT monrect = rect_from_cgrect(displays[i].frame);
439             RECT unused;
440             if (!rect || IntersectRect(&unused, &monrect, rect))
441             {
442                 HMONITOR monitor = display_id_to_monitor(displays[i].displayID);
443                 TRACE("monitor %d handle %p @ %s\n", i, monitor, wine_dbgstr_rect(&monrect));
444                 if (!proc(monitor, 0, &monrect, lparam))
445                 {
446                     ret = FALSE;
447                     break;
448                 }
449             }
450         }
451     }
452
453     macdrv_free_displays(displays);
454
455     return ret;
456 }
457
458
459 /***********************************************************************
460  *              EnumDisplaySettingsEx  (MACDRV.@)
461  *
462  */
463 BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode,
464                                         LPDEVMODEW devmode, DWORD flags)
465 {
466     static const WCHAR dev_name[CCHDEVICENAME] =
467         { 'W','i','n','e',' ','M','a','c',' ','d','r','i','v','e','r',0 };
468     struct macdrv_display *displays = NULL;
469     int num_displays;
470     CGDisplayModeRef display_mode;
471     double rotation;
472     uint32_t io_flags;
473
474     TRACE("%s, %u, %p + %hu, %08x\n", debugstr_w(devname), mode, devmode, devmode->dmSize, flags);
475
476     memcpy(devmode->dmDeviceName, dev_name, sizeof(dev_name));
477     devmode->dmSpecVersion = DM_SPECVERSION;
478     devmode->dmDriverVersion = DM_SPECVERSION;
479     devmode->dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod);
480     devmode->dmDriverExtra = 0;
481     memset(&devmode->dmFields, 0, devmode->dmSize - FIELD_OFFSET(DEVMODEW, dmFields));
482
483     if (mode == ENUM_REGISTRY_SETTINGS)
484     {
485         TRACE("mode %d (registry) -- getting default mode\n", mode);
486         return read_registry_settings(devmode);
487     }
488
489     if (macdrv_get_displays(&displays, &num_displays))
490         goto failed;
491
492     if (mode == ENUM_CURRENT_SETTINGS)
493     {
494         TRACE("mode %d (current) -- getting current mode\n", mode);
495         display_mode = CGDisplayCopyDisplayMode(displays[0].displayID);
496     }
497     else
498     {
499         EnterCriticalSection(&modes_section);
500
501         if (mode == 0 || !modes)
502         {
503             if (modes) CFRelease(modes);
504             modes = CGDisplayCopyAllDisplayModes(displays[0].displayID, NULL);
505         }
506
507         display_mode = NULL;
508         if (modes)
509         {
510             if (flags & EDS_RAWMODE)
511             {
512                 if (mode < CFArrayGetCount(modes))
513                     display_mode = (CGDisplayModeRef)CFRetain(CFArrayGetValueAtIndex(modes, mode));
514             }
515             else
516             {
517                 DWORD count, i, safe_modes = 0;
518                 count = CFArrayGetCount(modes);
519                 for (i = 0; i < count; i++)
520                 {
521                     CGDisplayModeRef candidate = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i);
522                     io_flags = CGDisplayModeGetIOFlags(candidate);
523                     if ((io_flags & kDisplayModeValidFlag) &&
524                         (io_flags & kDisplayModeSafeFlag))
525                     {
526                         safe_modes++;
527                         if (safe_modes > mode)
528                         {
529                             display_mode = (CGDisplayModeRef)CFRetain(candidate);
530                             break;
531                         }
532                     }
533                 }
534             }
535         }
536
537         LeaveCriticalSection(&modes_section);
538     }
539
540     if (!display_mode)
541         goto failed;
542
543     /* We currently only report modes for the primary display, so it's at (0, 0). */
544     devmode->dmPosition.x = 0;
545     devmode->dmPosition.y = 0;
546     devmode->dmFields |= DM_POSITION;
547
548     rotation = CGDisplayRotation(displays[0].displayID);
549     devmode->dmDisplayOrientation = ((int)((rotation / 90) + 0.5)) % 4;
550     devmode->dmFields |= DM_DISPLAYORIENTATION;
551
552     io_flags = CGDisplayModeGetIOFlags(display_mode);
553     if (io_flags & kDisplayModeStretchedFlag)
554         devmode->dmDisplayFixedOutput = DMDFO_STRETCH;
555     else
556         devmode->dmDisplayFixedOutput = DMDFO_CENTER;
557     devmode->dmFields |= DM_DISPLAYFIXEDOUTPUT;
558
559     devmode->dmBitsPerPel = display_mode_bits_per_pixel(display_mode);
560     if (devmode->dmBitsPerPel)
561         devmode->dmFields |= DM_BITSPERPEL;
562
563     devmode->dmPelsWidth = CGDisplayModeGetWidth(display_mode);
564     devmode->dmPelsHeight = CGDisplayModeGetHeight(display_mode);
565     devmode->dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
566
567     devmode->dmDisplayFlags = 0;
568     if (io_flags & kDisplayModeInterlacedFlag)
569         devmode->dmDisplayFlags |= DM_INTERLACED;
570     devmode->dmFields |= DM_DISPLAYFLAGS;
571
572     devmode->dmDisplayFrequency = CGDisplayModeGetRefreshRate(display_mode);
573     if (!devmode->dmDisplayFrequency)
574         devmode->dmDisplayFrequency = 60;
575     devmode->dmFields |= DM_DISPLAYFREQUENCY;
576
577     CFRelease(display_mode);
578     macdrv_free_displays(displays);
579
580     TRACE("mode %d -- %dx%dx%dbpp @%d Hz", mode,
581           devmode->dmPelsWidth, devmode->dmPelsHeight, devmode->dmBitsPerPel,
582           devmode->dmDisplayFrequency);
583     if (devmode->dmDisplayOrientation)
584         TRACE(" rotated %u degrees", devmode->dmDisplayOrientation * 90);
585     if (devmode->dmDisplayFixedOutput == DMDFO_STRETCH)
586         TRACE(" stretched");
587     if (devmode->dmDisplayFlags & DM_INTERLACED)
588         TRACE(" interlaced");
589     TRACE("\n");
590
591     return TRUE;
592
593 failed:
594     TRACE("mode %d -- not present\n", mode);
595     if (displays) macdrv_free_displays(displays);
596     SetLastError(ERROR_NO_MORE_FILES);
597     return FALSE;
598 }
599
600
601 /***********************************************************************
602  *              GetMonitorInfo  (MACDRV.@)
603  */
604 BOOL CDECL macdrv_GetMonitorInfo(HMONITOR monitor, LPMONITORINFO info)
605 {
606     static const WCHAR adapter_name[] = { '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 };
607     struct macdrv_display *displays;
608     int num_displays;
609     CGDirectDisplayID display_id;
610     int i;
611
612     TRACE("%p, %p\n", monitor, info);
613
614     if (macdrv_get_displays(&displays, &num_displays))
615     {
616         ERR("couldn't get display list\n");
617         SetLastError(ERROR_GEN_FAILURE);
618         return FALSE;
619     }
620
621     display_id = monitor_to_display_id(monitor);
622     for (i = 0; i < num_displays; i++)
623     {
624         if (displays[i].displayID == display_id)
625             break;
626     }
627
628     if (i < num_displays)
629     {
630         info->rcMonitor = rect_from_cgrect(displays[i].frame);
631         info->rcWork    = rect_from_cgrect(displays[i].work_frame);
632
633         info->dwFlags = (i == 0) ? MONITORINFOF_PRIMARY : 0;
634
635         if (info->cbSize >= sizeof(MONITORINFOEXW))
636             lstrcpyW(((MONITORINFOEXW*)info)->szDevice, adapter_name);
637
638         TRACE(" -> rcMonitor %s rcWork %s dwFlags %08x\n", wine_dbgstr_rect(&info->rcMonitor),
639               wine_dbgstr_rect(&info->rcWork), info->dwFlags);
640     }
641     else
642     {
643         ERR("invalid monitor handle\n");
644         SetLastError(ERROR_INVALID_HANDLE);
645     }
646
647     macdrv_free_displays(displays);
648     return (i < num_displays);
649 }
650
651
652 /***********************************************************************
653  *              macdrv_displays_changed
654  *
655  * Handler for DISPLAYS_CHANGED events.
656  */
657 void macdrv_displays_changed(const macdrv_event *event)
658 {
659     HWND hwnd = GetDesktopWindow();
660
661     /* A system display change will get delivered to all GUI-attached threads,
662        so the desktop-window-owning thread will get it and all others should
663        ignore it.  A synthesized display change event due to activation
664        will only get delivered to the activated process.  So, it needs to
665        process it (by sending it to the desktop window). */
666     if (event->displays_changed.activating ||
667         GetWindowThreadProcessId(hwnd, NULL) == GetCurrentThreadId())
668     {
669         CGDirectDisplayID mainDisplay = CGMainDisplayID();
670         CGDisplayModeRef mode = CGDisplayCopyDisplayMode(mainDisplay);
671         size_t width = CGDisplayModeGetWidth(mode);
672         size_t height = CGDisplayModeGetHeight(mode);
673         int mode_bpp = display_mode_bits_per_pixel(mode);
674
675         CGDisplayModeRelease(mode);
676         SendMessageW(hwnd, WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
677                      MAKELPARAM(width, height));
678     }
679 }