wininet: Added support for raw deflate content encoding.
[wine/multimedia.git] / dlls / winemac.drv / display.c
blob2f801f06fc4a98756f38f6cfc5889a74f91ad379
1 /*
2 * MACDRV display settings
4 * Copyright 2003 Alexander James Pasadyn
5 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
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.
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.
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
22 #include "config.h"
24 #include "macdrv.h"
25 #include "winuser.h"
26 #include "winreg.h"
27 #include "ddrawi.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(display);
32 BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW devmode, DWORD flags);
35 static CFArrayRef modes;
36 static BOOL modes_has_8bpp, modes_has_16bpp;
37 static int default_mode_bpp;
38 static CRITICAL_SECTION modes_section;
39 static CRITICAL_SECTION_DEBUG critsect_debug =
41 0, 0, &modes_section,
42 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
43 0, 0, { (DWORD_PTR)(__FILE__ ": modes_section") }
45 static CRITICAL_SECTION modes_section = { &critsect_debug, -1, 0, 0, 0, 0 };
48 static inline HMONITOR display_id_to_monitor(CGDirectDisplayID display_id)
50 return (HMONITOR)(UINT_PTR)display_id;
53 static inline CGDirectDisplayID monitor_to_display_id(HMONITOR handle)
55 return (CGDirectDisplayID)(UINT_PTR)handle;
59 static BOOL get_display_device_reg_key(char *key, unsigned len)
61 static const char display_device_guid_prop[] = "__wine_display_device_guid";
62 static const char video_path[] = "System\\CurrentControlSet\\Control\\Video\\{";
63 static const char display0[] = "}\\0000";
64 ATOM guid_atom;
66 assert(len >= sizeof(video_path) + sizeof(display0) + 40);
68 guid_atom = HandleToULong(GetPropA(GetDesktopWindow(), display_device_guid_prop));
69 if (!guid_atom) return FALSE;
71 memcpy(key, video_path, sizeof(video_path));
73 if (!GlobalGetAtomNameA(guid_atom, key + strlen(key), 40))
74 return FALSE;
76 strcat(key, display0);
78 TRACE("display device key %s\n", wine_dbgstr_a(key));
79 return TRUE;
83 static BOOL read_registry_settings(DEVMODEW *dm)
85 char wine_mac_reg_key[128];
86 HKEY hkey;
87 DWORD type, size;
88 BOOL ret = TRUE;
90 dm->dmFields = 0;
92 if (!get_display_device_reg_key(wine_mac_reg_key, sizeof(wine_mac_reg_key)))
93 return FALSE;
95 if (RegOpenKeyExA(HKEY_CURRENT_CONFIG, wine_mac_reg_key, 0, KEY_READ, &hkey))
96 return FALSE;
98 #define query_value(name, data) \
99 size = sizeof(DWORD); \
100 if (RegQueryValueExA(hkey, name, 0, &type, (LPBYTE)(data), &size) || \
101 type != REG_DWORD || size != sizeof(DWORD)) \
102 ret = FALSE
104 query_value("DefaultSettings.BitsPerPel", &dm->dmBitsPerPel);
105 dm->dmFields |= DM_BITSPERPEL;
106 query_value("DefaultSettings.XResolution", &dm->dmPelsWidth);
107 dm->dmFields |= DM_PELSWIDTH;
108 query_value("DefaultSettings.YResolution", &dm->dmPelsHeight);
109 dm->dmFields |= DM_PELSHEIGHT;
110 query_value("DefaultSettings.VRefresh", &dm->dmDisplayFrequency);
111 dm->dmFields |= DM_DISPLAYFREQUENCY;
112 query_value("DefaultSettings.Flags", &dm->dmDisplayFlags);
113 dm->dmFields |= DM_DISPLAYFLAGS;
114 query_value("DefaultSettings.XPanning", &dm->dmPosition.x);
115 query_value("DefaultSettings.YPanning", &dm->dmPosition.y);
116 query_value("DefaultSettings.Orientation", &dm->dmDisplayOrientation);
117 query_value("DefaultSettings.FixedOutput", &dm->dmDisplayFixedOutput);
119 #undef query_value
121 RegCloseKey(hkey);
122 return ret;
126 static BOOL write_registry_settings(const DEVMODEW *dm)
128 char wine_mac_reg_key[128];
129 HKEY hkey;
130 BOOL ret = TRUE;
132 if (!get_display_device_reg_key(wine_mac_reg_key, sizeof(wine_mac_reg_key)))
133 return FALSE;
135 if (RegCreateKeyExA(HKEY_CURRENT_CONFIG, wine_mac_reg_key, 0, NULL,
136 REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, NULL))
137 return FALSE;
139 #define set_value(name, data) \
140 if (RegSetValueExA(hkey, name, 0, REG_DWORD, (const BYTE*)(data), sizeof(DWORD))) \
141 ret = FALSE
143 set_value("DefaultSettings.BitsPerPel", &dm->dmBitsPerPel);
144 set_value("DefaultSettings.XResolution", &dm->dmPelsWidth);
145 set_value("DefaultSettings.YResolution", &dm->dmPelsHeight);
146 set_value("DefaultSettings.VRefresh", &dm->dmDisplayFrequency);
147 set_value("DefaultSettings.Flags", &dm->dmDisplayFlags);
148 set_value("DefaultSettings.XPanning", &dm->dmPosition.x);
149 set_value("DefaultSettings.YPanning", &dm->dmPosition.y);
150 set_value("DefaultSettings.Orientation", &dm->dmDisplayOrientation);
151 set_value("DefaultSettings.FixedOutput", &dm->dmDisplayFixedOutput);
153 #undef set_value
155 RegCloseKey(hkey);
156 return ret;
160 static int display_mode_bits_per_pixel(CGDisplayModeRef display_mode)
162 CFStringRef pixel_encoding;
163 int bits_per_pixel = 0;
165 pixel_encoding = CGDisplayModeCopyPixelEncoding(display_mode);
166 if (pixel_encoding)
168 if (CFEqual(pixel_encoding, CFSTR(kIO32BitFloatPixels)))
169 bits_per_pixel = 128;
170 else if (CFEqual(pixel_encoding, CFSTR(kIO16BitFloatPixels)))
171 bits_per_pixel = 64;
172 else if (CFEqual(pixel_encoding, CFSTR(kIO64BitDirectPixels)))
173 bits_per_pixel = 64;
174 else if (CFEqual(pixel_encoding, CFSTR(kIO30BitDirectPixels)))
175 bits_per_pixel = 30;
176 else if (CFEqual(pixel_encoding, CFSTR(IO32BitDirectPixels)))
177 bits_per_pixel = 32;
178 else if (CFEqual(pixel_encoding, CFSTR(IO16BitDirectPixels)))
179 bits_per_pixel = 16;
180 else if (CFEqual(pixel_encoding, CFSTR(IO8BitIndexedPixels)))
181 bits_per_pixel = 8;
182 else if (CFEqual(pixel_encoding, CFSTR(IO4BitIndexedPixels)))
183 bits_per_pixel = 4;
184 else if (CFEqual(pixel_encoding, CFSTR(IO2BitIndexedPixels)))
185 bits_per_pixel = 2;
186 else if (CFEqual(pixel_encoding, CFSTR(IO1BitIndexedPixels)))
187 bits_per_pixel = 1;
189 CFRelease(pixel_encoding);
192 return bits_per_pixel;
196 static int get_default_bpp(void)
198 int ret;
200 EnterCriticalSection(&modes_section);
202 if (!default_mode_bpp)
204 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(kCGDirectMainDisplay);
205 if (mode)
207 default_mode_bpp = display_mode_bits_per_pixel(mode);
208 CFRelease(mode);
211 if (!default_mode_bpp)
212 default_mode_bpp = 32;
215 ret = default_mode_bpp;
217 LeaveCriticalSection(&modes_section);
219 TRACE(" -> %d\n", ret);
220 return ret;
224 /***********************************************************************
225 * ChangeDisplaySettingsEx (MACDRV.@)
228 LONG CDECL macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
229 HWND hwnd, DWORD flags, LPVOID lpvoid)
231 LONG ret = DISP_CHANGE_BADMODE;
232 int bpp;
233 DEVMODEW dm;
234 BOOL def_mode = TRUE;
235 struct macdrv_display *displays;
236 int num_displays;
237 CFArrayRef display_modes;
238 CFIndex count, i, safe, best;
239 CGDisplayModeRef best_display_mode;
240 uint32_t best_io_flags;
242 TRACE("%s %p %p 0x%08x %p\n", debugstr_w(devname), devmode, hwnd, flags, lpvoid);
244 if (devmode)
246 /* this is the minimal dmSize that XP accepts */
247 if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmFields))
248 return DISP_CHANGE_FAILED;
250 if (devmode->dmSize >= FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(devmode->dmFields))
252 if (((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
253 ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
254 ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
255 ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
256 def_mode = FALSE;
260 if (def_mode)
262 if (!macdrv_EnumDisplaySettingsEx(devname, ENUM_REGISTRY_SETTINGS, &dm, 0))
264 ERR("Default mode not found!\n");
265 return DISP_CHANGE_BADMODE;
268 TRACE("Return to original display mode\n");
269 devmode = &dm;
272 if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
274 WARN("devmode doesn't specify the resolution: %04x\n", devmode->dmFields);
275 return DISP_CHANGE_BADMODE;
278 if (macdrv_get_displays(&displays, &num_displays))
279 return DISP_CHANGE_FAILED;
281 display_modes = CGDisplayCopyAllDisplayModes(displays[0].displayID, NULL);
282 if (!display_modes)
284 macdrv_free_displays(displays);
285 return DISP_CHANGE_FAILED;
288 bpp = get_default_bpp();
289 if ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel != bpp)
290 TRACE("using default %d bpp instead of caller's request %d bpp\n", bpp, devmode->dmBitsPerPel);
292 TRACE("looking for %dx%dx%dbpp @%d Hz",
293 (devmode->dmFields & DM_PELSWIDTH ? devmode->dmPelsWidth : 0),
294 (devmode->dmFields & DM_PELSHEIGHT ? devmode->dmPelsHeight : 0),
295 bpp,
296 (devmode->dmFields & DM_DISPLAYFREQUENCY ? devmode->dmDisplayFrequency : 0));
297 if (devmode->dmFields & DM_DISPLAYFIXEDOUTPUT)
298 TRACE(" %sstretched", devmode->dmDisplayFixedOutput == DMDFO_STRETCH ? "" : "un");
299 if (devmode->dmFields & DM_DISPLAYFLAGS)
300 TRACE(" %sinterlaced", devmode->dmDisplayFlags & DM_INTERLACED ? "" : "non-");
301 TRACE("\n");
303 safe = -1;
304 best_display_mode = NULL;
305 count = CFArrayGetCount(display_modes);
306 for (i = 0; i < count; i++)
308 CGDisplayModeRef display_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(display_modes, i);
309 uint32_t io_flags = CGDisplayModeGetIOFlags(display_mode);
310 int mode_bpp = display_mode_bits_per_pixel(display_mode);
311 size_t width = CGDisplayModeGetWidth(display_mode);
312 size_t height = CGDisplayModeGetHeight(display_mode);
314 if (!(io_flags & kDisplayModeValidFlag) || !(io_flags & kDisplayModeSafeFlag))
315 continue;
317 safe++;
319 if (bpp != mode_bpp)
320 continue;
322 if (devmode->dmFields & DM_PELSWIDTH)
324 if (devmode->dmPelsWidth != width)
325 continue;
327 if (devmode->dmFields & DM_PELSHEIGHT)
329 if (devmode->dmPelsHeight != height)
330 continue;
332 if ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency != 0)
334 double refresh_rate = CGDisplayModeGetRefreshRate(display_mode);
335 if (!refresh_rate)
336 refresh_rate = 60;
337 if (devmode->dmDisplayFrequency != (DWORD)refresh_rate)
338 continue;
340 if (devmode->dmFields & DM_DISPLAYFLAGS)
342 if (!(devmode->dmDisplayFlags & DM_INTERLACED) != !(io_flags & kDisplayModeInterlacedFlag))
343 continue;
345 else if (best_display_mode)
347 if (io_flags & kDisplayModeInterlacedFlag && !(best_io_flags & kDisplayModeInterlacedFlag))
348 continue;
349 else if (!(io_flags & kDisplayModeInterlacedFlag) && best_io_flags & kDisplayModeInterlacedFlag)
350 goto better;
352 if (devmode->dmFields & DM_DISPLAYFIXEDOUTPUT)
354 if (!(devmode->dmDisplayFixedOutput == DMDFO_STRETCH) != !(io_flags & kDisplayModeStretchedFlag))
355 continue;
357 else if (best_display_mode)
359 if (io_flags & kDisplayModeStretchedFlag && !(best_io_flags & kDisplayModeStretchedFlag))
360 continue;
361 else if (!(io_flags & kDisplayModeStretchedFlag) && best_io_flags & kDisplayModeStretchedFlag)
362 goto better;
365 if (best_display_mode)
366 continue;
368 better:
369 best_display_mode = display_mode;
370 best = safe;
371 best_io_flags = io_flags;
374 if (best_display_mode)
376 /* we have a valid mode */
377 TRACE("Requested display settings match mode %ld\n", best);
379 if ((flags & CDS_UPDATEREGISTRY) && !write_registry_settings(devmode))
381 WARN("Failed to update registry\n");
382 ret = DISP_CHANGE_NOTUPDATED;
384 else if (flags & (CDS_TEST | CDS_NORESET))
385 ret = DISP_CHANGE_SUCCESSFUL;
386 else if (macdrv_set_display_mode(&displays[0], best_display_mode))
388 int mode_bpp = display_mode_bits_per_pixel(best_display_mode);
389 size_t width = CGDisplayModeGetWidth(best_display_mode);
390 size_t height = CGDisplayModeGetHeight(best_display_mode);
392 SendMessageW(GetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
393 MAKELPARAM(width, height));
394 ret = DISP_CHANGE_SUCCESSFUL;
396 else
398 WARN("Failed to set display mode\n");
399 ret = DISP_CHANGE_FAILED;
402 else
404 /* no valid modes found */
405 ERR("No matching mode found %ux%ux%d @%u!\n", devmode->dmPelsWidth, devmode->dmPelsHeight,
406 bpp, devmode->dmDisplayFrequency);
409 CFRelease(display_modes);
410 macdrv_free_displays(displays);
412 return ret;
416 /***********************************************************************
417 * EnumDisplayMonitors (MACDRV.@)
419 BOOL CDECL macdrv_EnumDisplayMonitors(HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lparam)
421 struct macdrv_display *displays;
422 int num_displays;
423 int i;
424 BOOL ret = TRUE;
426 TRACE("%p, %s, %p, %#lx\n", hdc, wine_dbgstr_rect(rect), proc, lparam);
428 if (hdc)
430 POINT origin;
431 RECT limit;
433 if (!GetDCOrgEx(hdc, &origin)) return FALSE;
434 if (GetClipBox(hdc, &limit) == ERROR) return FALSE;
436 if (rect && !IntersectRect(&limit, &limit, rect)) return TRUE;
438 if (macdrv_get_displays(&displays, &num_displays))
439 return FALSE;
441 for (i = 0; i < num_displays; i++)
443 RECT monrect = rect_from_cgrect(displays[i].frame);
444 OffsetRect(&monrect, -origin.x, -origin.y);
445 if (IntersectRect(&monrect, &monrect, &limit))
447 HMONITOR monitor = display_id_to_monitor(displays[i].displayID);
448 TRACE("monitor %d handle %p @ %s\n", i, monitor, wine_dbgstr_rect(&monrect));
449 if (!proc(monitor, hdc, &monrect, lparam))
451 ret = FALSE;
452 break;
457 else
459 if (macdrv_get_displays(&displays, &num_displays))
460 return FALSE;
462 for (i = 0; i < num_displays; i++)
464 RECT monrect = rect_from_cgrect(displays[i].frame);
465 RECT unused;
466 if (!rect || IntersectRect(&unused, &monrect, rect))
468 HMONITOR monitor = display_id_to_monitor(displays[i].displayID);
469 TRACE("monitor %d handle %p @ %s\n", i, monitor, wine_dbgstr_rect(&monrect));
470 if (!proc(monitor, 0, &monrect, lparam))
472 ret = FALSE;
473 break;
479 macdrv_free_displays(displays);
481 return ret;
485 /***********************************************************************
486 * EnumDisplaySettingsEx (MACDRV.@)
489 BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode,
490 LPDEVMODEW devmode, DWORD flags)
492 static const WCHAR dev_name[CCHDEVICENAME] =
493 { 'W','i','n','e',' ','M','a','c',' ','d','r','i','v','e','r',0 };
494 struct macdrv_display *displays = NULL;
495 int num_displays;
496 CGDisplayModeRef display_mode;
497 int display_mode_bpp;
498 BOOL synthesized = FALSE;
499 double rotation;
500 uint32_t io_flags;
502 TRACE("%s, %u, %p + %hu, %08x\n", debugstr_w(devname), mode, devmode, devmode->dmSize, flags);
504 memcpy(devmode->dmDeviceName, dev_name, sizeof(dev_name));
505 devmode->dmSpecVersion = DM_SPECVERSION;
506 devmode->dmDriverVersion = DM_SPECVERSION;
507 devmode->dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod);
508 devmode->dmDriverExtra = 0;
509 memset(&devmode->dmFields, 0, devmode->dmSize - FIELD_OFFSET(DEVMODEW, dmFields));
511 if (mode == ENUM_REGISTRY_SETTINGS)
513 TRACE("mode %d (registry) -- getting default mode\n", mode);
514 return read_registry_settings(devmode);
517 if (macdrv_get_displays(&displays, &num_displays))
518 goto failed;
520 if (mode == ENUM_CURRENT_SETTINGS)
522 TRACE("mode %d (current) -- getting current mode\n", mode);
523 display_mode = CGDisplayCopyDisplayMode(displays[0].displayID);
524 display_mode_bpp = display_mode_bits_per_pixel(display_mode);
526 else
528 DWORD count, i;
530 EnterCriticalSection(&modes_section);
532 if (mode == 0 || !modes)
534 if (modes) CFRelease(modes);
535 modes = CGDisplayCopyAllDisplayModes(displays[0].displayID, NULL);
536 modes_has_8bpp = modes_has_16bpp = FALSE;
538 if (modes)
540 count = CFArrayGetCount(modes);
541 for (i = 0; i < count && !(modes_has_8bpp && modes_has_16bpp); i++)
543 CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i);
544 int bpp = display_mode_bits_per_pixel(mode);
545 if (bpp == 8)
546 modes_has_8bpp = TRUE;
547 else if (bpp == 16)
548 modes_has_16bpp = TRUE;
553 display_mode = NULL;
554 if (modes)
556 int default_bpp = get_default_bpp();
557 DWORD seen_modes = 0;
559 count = CFArrayGetCount(modes);
560 for (i = 0; i < count; i++)
562 CGDisplayModeRef candidate = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i);
564 io_flags = CGDisplayModeGetIOFlags(candidate);
565 if (!(flags & EDS_RAWMODE) &&
566 (!(io_flags & kDisplayModeValidFlag) || !(io_flags & kDisplayModeSafeFlag)))
567 continue;
569 seen_modes++;
570 if (seen_modes > mode)
572 display_mode = (CGDisplayModeRef)CFRetain(candidate);
573 display_mode_bpp = display_mode_bits_per_pixel(display_mode);
574 break;
577 /* We only synthesize modes from those having the default bpp. */
578 if (display_mode_bits_per_pixel(candidate) != default_bpp)
579 continue;
581 if (!modes_has_8bpp)
583 seen_modes++;
584 if (seen_modes > mode)
586 display_mode = (CGDisplayModeRef)CFRetain(candidate);
587 display_mode_bpp = 8;
588 synthesized = TRUE;
589 break;
593 if (!modes_has_16bpp)
595 seen_modes++;
596 if (seen_modes > mode)
598 display_mode = (CGDisplayModeRef)CFRetain(candidate);
599 display_mode_bpp = 16;
600 synthesized = TRUE;
601 break;
607 LeaveCriticalSection(&modes_section);
610 if (!display_mode)
611 goto failed;
613 /* We currently only report modes for the primary display, so it's at (0, 0). */
614 devmode->dmPosition.x = 0;
615 devmode->dmPosition.y = 0;
616 devmode->dmFields |= DM_POSITION;
618 rotation = CGDisplayRotation(displays[0].displayID);
619 devmode->dmDisplayOrientation = ((int)((rotation / 90) + 0.5)) % 4;
620 devmode->dmFields |= DM_DISPLAYORIENTATION;
622 io_flags = CGDisplayModeGetIOFlags(display_mode);
623 if (io_flags & kDisplayModeStretchedFlag)
624 devmode->dmDisplayFixedOutput = DMDFO_STRETCH;
625 else
626 devmode->dmDisplayFixedOutput = DMDFO_CENTER;
627 devmode->dmFields |= DM_DISPLAYFIXEDOUTPUT;
629 devmode->dmBitsPerPel = display_mode_bpp;
630 if (devmode->dmBitsPerPel)
631 devmode->dmFields |= DM_BITSPERPEL;
633 devmode->dmPelsWidth = CGDisplayModeGetWidth(display_mode);
634 devmode->dmPelsHeight = CGDisplayModeGetHeight(display_mode);
635 devmode->dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
637 devmode->dmDisplayFlags = 0;
638 if (io_flags & kDisplayModeInterlacedFlag)
639 devmode->dmDisplayFlags |= DM_INTERLACED;
640 devmode->dmFields |= DM_DISPLAYFLAGS;
642 devmode->dmDisplayFrequency = CGDisplayModeGetRefreshRate(display_mode);
643 if (!devmode->dmDisplayFrequency)
644 devmode->dmDisplayFrequency = 60;
645 devmode->dmFields |= DM_DISPLAYFREQUENCY;
647 CFRelease(display_mode);
648 macdrv_free_displays(displays);
650 TRACE("mode %d -- %dx%dx%dbpp @%d Hz", mode,
651 devmode->dmPelsWidth, devmode->dmPelsHeight, devmode->dmBitsPerPel,
652 devmode->dmDisplayFrequency);
653 if (devmode->dmDisplayOrientation)
654 TRACE(" rotated %u degrees", devmode->dmDisplayOrientation * 90);
655 if (devmode->dmDisplayFixedOutput == DMDFO_STRETCH)
656 TRACE(" stretched");
657 if (devmode->dmDisplayFlags & DM_INTERLACED)
658 TRACE(" interlaced");
659 if (synthesized)
660 TRACE(" (synthesized)");
661 TRACE("\n");
663 return TRUE;
665 failed:
666 TRACE("mode %d -- not present\n", mode);
667 if (displays) macdrv_free_displays(displays);
668 SetLastError(ERROR_NO_MORE_FILES);
669 return FALSE;
673 /***********************************************************************
674 * GetDeviceGammaRamp (MACDRV.@)
676 BOOL macdrv_GetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp)
678 BOOL ret = FALSE;
679 DDGAMMARAMP *r = ramp;
680 struct macdrv_display *displays;
681 int num_displays;
682 uint32_t mac_entries;
683 int win_entries = sizeof(r->red) / sizeof(r->red[0]);
684 CGGammaValue *red, *green, *blue;
685 CGError err;
686 int win_entry;
688 TRACE("dev %p ramp %p\n", dev, ramp);
690 if (macdrv_get_displays(&displays, &num_displays))
692 WARN("failed to get Mac displays\n");
693 return FALSE;
696 mac_entries = CGDisplayGammaTableCapacity(displays[0].displayID);
697 red = HeapAlloc(GetProcessHeap(), 0, mac_entries * sizeof(red[0]) * 3);
698 if (!red)
699 goto done;
700 green = red + mac_entries;
701 blue = green + mac_entries;
703 err = CGGetDisplayTransferByTable(displays[0].displayID, mac_entries, red, green,
704 blue, &mac_entries);
705 if (err != kCGErrorSuccess)
707 WARN("failed to get Mac gamma table: %d\n", err);
708 goto done;
711 if (mac_entries == win_entries)
713 for (win_entry = 0; win_entry < win_entries; win_entry++)
715 r->red[win_entry] = red[win_entry] * 65535 + 0.5;
716 r->green[win_entry] = green[win_entry] * 65535 + 0.5;
717 r->blue[win_entry] = blue[win_entry] * 65535 + 0.5;
720 else
722 for (win_entry = 0; win_entry < win_entries; win_entry++)
724 double mac_pos = win_entry * (mac_entries - 1) / (double)(win_entries - 1);
725 int mac_entry = mac_pos;
726 double red_value, green_value, blue_value;
728 if (mac_entry == mac_entries - 1)
730 red_value = red[mac_entry];
731 green_value = green[mac_entry];
732 blue_value = blue[mac_entry];
734 else
736 double distance = mac_pos - mac_entry;
738 red_value = red[mac_entry] * (1 - distance) + red[mac_entry + 1] * distance;
739 green_value = green[mac_entry] * (1 - distance) + green[mac_entry + 1] * distance;
740 blue_value = blue[mac_entry] * (1 - distance) + blue[mac_entry + 1] * distance;
743 r->red[win_entry] = red_value * 65535 + 0.5;
744 r->green[win_entry] = green_value * 65535 + 0.5;
745 r->blue[win_entry] = blue_value * 65535 + 0.5;
749 ret = TRUE;
751 done:
752 HeapFree(GetProcessHeap(), 0, red);
753 macdrv_free_displays(displays);
754 return ret;
758 /***********************************************************************
759 * GetMonitorInfo (MACDRV.@)
761 BOOL CDECL macdrv_GetMonitorInfo(HMONITOR monitor, LPMONITORINFO info)
763 static const WCHAR adapter_name[] = { '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 };
764 struct macdrv_display *displays;
765 int num_displays;
766 CGDirectDisplayID display_id;
767 int i;
769 TRACE("%p, %p\n", monitor, info);
771 if (macdrv_get_displays(&displays, &num_displays))
773 ERR("couldn't get display list\n");
774 SetLastError(ERROR_GEN_FAILURE);
775 return FALSE;
778 display_id = monitor_to_display_id(monitor);
779 for (i = 0; i < num_displays; i++)
781 if (displays[i].displayID == display_id)
782 break;
785 if (i < num_displays)
787 info->rcMonitor = rect_from_cgrect(displays[i].frame);
788 info->rcWork = rect_from_cgrect(displays[i].work_frame);
790 info->dwFlags = (i == 0) ? MONITORINFOF_PRIMARY : 0;
792 if (info->cbSize >= sizeof(MONITORINFOEXW))
793 lstrcpyW(((MONITORINFOEXW*)info)->szDevice, adapter_name);
795 TRACE(" -> rcMonitor %s rcWork %s dwFlags %08x\n", wine_dbgstr_rect(&info->rcMonitor),
796 wine_dbgstr_rect(&info->rcWork), info->dwFlags);
798 else
800 ERR("invalid monitor handle\n");
801 SetLastError(ERROR_INVALID_HANDLE);
804 macdrv_free_displays(displays);
805 return (i < num_displays);
809 /***********************************************************************
810 * SetDeviceGammaRamp (MACDRV.@)
812 BOOL macdrv_SetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp)
814 DDGAMMARAMP *r = ramp;
815 struct macdrv_display *displays;
816 int num_displays;
817 int win_entries = sizeof(r->red) / sizeof(r->red[0]);
818 CGGammaValue *red, *green, *blue;
819 int i;
820 CGError err = kCGErrorFailure;
822 TRACE("dev %p ramp %p\n", dev, ramp);
824 if (!allow_set_gamma)
826 TRACE("disallowed by registry setting\n");
827 return FALSE;
830 if (macdrv_get_displays(&displays, &num_displays))
832 WARN("failed to get Mac displays\n");
833 return FALSE;
836 red = HeapAlloc(GetProcessHeap(), 0, win_entries * sizeof(red[0]) * 3);
837 if (!red)
838 goto done;
839 green = red + win_entries;
840 blue = green + win_entries;
842 for (i = 0; i < win_entries; i++)
844 red[i] = r->red[i] / 65535.0;
845 green[i] = r->green[i] / 65535.0;
846 blue[i] = r->blue[i] / 65535.0;
849 err = CGSetDisplayTransferByTable(displays[0].displayID, win_entries, red, green, blue);
850 if (err != kCGErrorSuccess)
851 WARN("failed to set display gamma table: %d\n", err);
853 done:
854 HeapFree(GetProcessHeap(), 0, red);
855 macdrv_free_displays(displays);
856 return (err == kCGErrorSuccess);
860 /***********************************************************************
861 * macdrv_displays_changed
863 * Handler for DISPLAYS_CHANGED events.
865 void macdrv_displays_changed(const macdrv_event *event)
867 HWND hwnd = GetDesktopWindow();
869 /* A system display change will get delivered to all GUI-attached threads,
870 so the desktop-window-owning thread will get it and all others should
871 ignore it. A synthesized display change event due to activation
872 will only get delivered to the activated process. So, it needs to
873 process it (by sending it to the desktop window). */
874 if (event->displays_changed.activating ||
875 GetWindowThreadProcessId(hwnd, NULL) == GetCurrentThreadId())
877 CGDirectDisplayID mainDisplay = CGMainDisplayID();
878 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(mainDisplay);
879 size_t width = CGDisplayModeGetWidth(mode);
880 size_t height = CGDisplayModeGetHeight(mode);
881 int mode_bpp = display_mode_bits_per_pixel(mode);
883 CGDisplayModeRelease(mode);
884 SendMessageW(hwnd, WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
885 MAKELPARAM(width, height));