2 * MACDRV initialization code
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2000 Alexandre Julliard
6 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <Security/AuthSession.h>
25 #include <IOKit/pwr_mgt/IOPMLib.h>
30 #include "wine/server.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(macdrv
);
34 #ifndef kIOPMAssertionTypePreventUserIdleDisplaySleep
35 #define kIOPMAssertionTypePreventUserIdleDisplaySleep CFSTR("PreventUserIdleDisplaySleep")
37 #ifndef kCFCoreFoundationVersionNumber10_7
38 #define kCFCoreFoundationVersionNumber10_7 635.00
41 #define IS_OPTION_TRUE(ch) \
42 ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
44 C_ASSERT(NUM_EVENT_TYPES
<= sizeof(macdrv_event_mask
) * 8);
46 DWORD thread_data_tls_index
= TLS_OUT_OF_INDEXES
;
48 int topmost_float_inactive
= TOPMOST_FLOAT_INACTIVE_NONFULLSCREEN
;
49 int capture_displays_for_fullscreen
= 0;
50 BOOL skip_single_buffer_flushes
= FALSE
;
51 BOOL allow_vsync
= TRUE
;
52 BOOL allow_set_gamma
= TRUE
;
53 int left_option_is_alt
= 0;
54 int right_option_is_alt
= 0;
55 int left_command_is_ctrl
= 0;
56 int right_command_is_ctrl
= 0;
57 BOOL allow_software_rendering
= FALSE
;
58 BOOL disable_window_decorations
= FALSE
;
59 int allow_immovable_windows
= TRUE
;
60 int cursor_clipping_locks_windows
= TRUE
;
61 int use_precise_scrolling
= TRUE
;
62 int gl_surface_mode
= GL_SURFACE_IN_FRONT_OPAQUE
;
63 int retina_enabled
= FALSE
;
64 HMODULE macdrv_module
= 0;
65 int enable_app_nap
= FALSE
;
67 CFDictionaryRef localized_strings
;
70 /**************************************************************************
73 const char* debugstr_cf(CFTypeRef t
)
78 if (!t
) return "(null)";
80 if (CFGetTypeID(t
) == CFStringGetTypeID())
83 s
= CFCopyDescription(t
);
84 ret
= CFStringGetCStringPtr(s
, kCFStringEncodingUTF8
);
85 if (ret
) ret
= debugstr_a(ret
);
88 const UniChar
* u
= CFStringGetCharactersPtr(s
);
90 ret
= debugstr_wn((const WCHAR
*)u
, CFStringGetLength(s
));
95 int len
= min(CFStringGetLength(s
), ARRAY_SIZE(buf
));
96 CFStringGetCharacters(s
, CFRangeMake(0, len
), buf
);
97 ret
= debugstr_wn(buf
, len
);
99 if (s
!= t
) CFRelease(s
);
104 /***********************************************************************
107 * Get a config key from either the app-specific or the default config
109 static inline DWORD
get_config_key(HKEY defkey
, HKEY appkey
, const char *name
,
110 char *buffer
, DWORD size
)
112 if (appkey
&& !RegQueryValueExA(appkey
, name
, 0, NULL
, (LPBYTE
)buffer
, &size
)) return 0;
113 if (defkey
&& !RegQueryValueExA(defkey
, name
, 0, NULL
, (LPBYTE
)buffer
, &size
)) return 0;
114 return ERROR_FILE_NOT_FOUND
;
118 /***********************************************************************
121 * Set up the Mac driver options.
123 static void setup_options(void)
125 char buffer
[MAX_PATH
+ 16];
126 HKEY hkey
, appkey
= 0;
129 /* @@ Wine registry key: HKCU\Software\Wine\Mac Driver */
130 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Mac Driver", &hkey
)) hkey
= 0;
132 /* open the app-specific key */
134 len
= GetModuleFileNameA(0, buffer
, MAX_PATH
);
135 if (len
&& len
< MAX_PATH
)
138 char *p
, *appname
= buffer
;
139 if ((p
= strrchr(appname
, '/'))) appname
= p
+ 1;
140 if ((p
= strrchr(appname
, '\\'))) appname
= p
+ 1;
141 strcat(appname
, "\\Mac Driver");
142 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Mac Driver */
143 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\AppDefaults", &tmpkey
))
145 if (RegOpenKeyA(tmpkey
, appname
, &appkey
)) appkey
= 0;
150 if (!get_config_key(hkey
, appkey
, "WindowsFloatWhenInactive", buffer
, sizeof(buffer
)))
152 if (!strcmp(buffer
, "none"))
153 topmost_float_inactive
= TOPMOST_FLOAT_INACTIVE_NONE
;
154 else if (!strcmp(buffer
, "all"))
155 topmost_float_inactive
= TOPMOST_FLOAT_INACTIVE_ALL
;
157 topmost_float_inactive
= TOPMOST_FLOAT_INACTIVE_NONFULLSCREEN
;
160 if (!get_config_key(hkey
, appkey
, "CaptureDisplaysForFullscreen", buffer
, sizeof(buffer
)))
161 capture_displays_for_fullscreen
= IS_OPTION_TRUE(buffer
[0]);
163 if (!get_config_key(hkey
, appkey
, "SkipSingleBufferFlushes", buffer
, sizeof(buffer
)))
164 skip_single_buffer_flushes
= IS_OPTION_TRUE(buffer
[0]);
166 if (!get_config_key(hkey
, appkey
, "AllowVerticalSync", buffer
, sizeof(buffer
)))
167 allow_vsync
= IS_OPTION_TRUE(buffer
[0]);
169 if (!get_config_key(hkey
, appkey
, "AllowSetGamma", buffer
, sizeof(buffer
)))
170 allow_set_gamma
= IS_OPTION_TRUE(buffer
[0]);
172 if (!get_config_key(hkey
, appkey
, "LeftOptionIsAlt", buffer
, sizeof(buffer
)))
173 left_option_is_alt
= IS_OPTION_TRUE(buffer
[0]);
174 if (!get_config_key(hkey
, appkey
, "RightOptionIsAlt", buffer
, sizeof(buffer
)))
175 right_option_is_alt
= IS_OPTION_TRUE(buffer
[0]);
177 if (!get_config_key(hkey
, appkey
, "LeftCommandIsCtrl", buffer
, sizeof(buffer
)))
178 left_command_is_ctrl
= IS_OPTION_TRUE(buffer
[0]);
179 if (!get_config_key(hkey
, appkey
, "RightCommandIsCtrl", buffer
, sizeof(buffer
)))
180 right_command_is_ctrl
= IS_OPTION_TRUE(buffer
[0]);
182 if (left_command_is_ctrl
&& right_command_is_ctrl
&& !left_option_is_alt
&& !right_option_is_alt
)
183 WARN("Both Command keys have been mapped to Control. There is no way to "
184 "send an Alt key to Windows applications. Consider enabling "
185 "LeftOptionIsAlt or RightOptionIsAlt.\n");
187 if (!get_config_key(hkey
, appkey
, "AllowSoftwareRendering", buffer
, sizeof(buffer
)))
188 allow_software_rendering
= IS_OPTION_TRUE(buffer
[0]);
190 /* Value name chosen to match what's used in the X11 driver. */
191 if (!get_config_key(hkey
, appkey
, "Decorated", buffer
, sizeof(buffer
)))
192 disable_window_decorations
= !IS_OPTION_TRUE(buffer
[0]);
194 if (!get_config_key(hkey
, appkey
, "AllowImmovableWindows", buffer
, sizeof(buffer
)))
195 allow_immovable_windows
= IS_OPTION_TRUE(buffer
[0]);
197 if (!get_config_key(hkey
, appkey
, "CursorClippingLocksWindows", buffer
, sizeof(buffer
)))
198 cursor_clipping_locks_windows
= IS_OPTION_TRUE(buffer
[0]);
200 if (!get_config_key(hkey
, appkey
, "UsePreciseScrolling", buffer
, sizeof(buffer
)))
201 use_precise_scrolling
= IS_OPTION_TRUE(buffer
[0]);
203 if (!get_config_key(hkey
, appkey
, "OpenGLSurfaceMode", buffer
, sizeof(buffer
)))
205 if (!strcmp(buffer
, "transparent"))
206 gl_surface_mode
= GL_SURFACE_IN_FRONT_TRANSPARENT
;
207 else if (!strcmp(buffer
, "behind"))
208 gl_surface_mode
= GL_SURFACE_BEHIND
;
210 gl_surface_mode
= GL_SURFACE_IN_FRONT_OPAQUE
;
213 if (!get_config_key(hkey
, appkey
, "EnableAppNap", buffer
, sizeof(buffer
)))
214 enable_app_nap
= IS_OPTION_TRUE(buffer
[0]);
216 /* Don't use appkey. The DPI and monitor sizes should be consistent for all
217 processes in the prefix. */
218 if (!get_config_key(hkey
, NULL
, "RetinaMode", buffer
, sizeof(buffer
)))
219 retina_enabled
= IS_OPTION_TRUE(buffer
[0]);
221 if (appkey
) RegCloseKey(appkey
);
222 if (hkey
) RegCloseKey(hkey
);
226 /***********************************************************************
229 static void load_strings(HINSTANCE instance
)
231 static const unsigned int ids
[] = {
233 STRING_MENU_ITEM_HIDE_APPNAME
,
234 STRING_MENU_ITEM_HIDE
,
235 STRING_MENU_ITEM_HIDE_OTHERS
,
236 STRING_MENU_ITEM_SHOW_ALL
,
237 STRING_MENU_ITEM_QUIT_APPNAME
,
238 STRING_MENU_ITEM_QUIT
,
241 STRING_MENU_ITEM_MINIMIZE
,
242 STRING_MENU_ITEM_ZOOM
,
243 STRING_MENU_ITEM_ENTER_FULL_SCREEN
,
244 STRING_MENU_ITEM_BRING_ALL_TO_FRONT
,
246 CFMutableDictionaryRef dict
;
249 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
250 &kCFTypeDictionaryValueCallBacks
);
253 ERR("Failed to create localized strings dictionary\n");
257 for (i
= 0; i
< ARRAY_SIZE(ids
); i
++)
260 int len
= LoadStringW(instance
, ids
[i
], (LPWSTR
)&str
, 0);
263 CFNumberRef key
= CFNumberCreate(NULL
, kCFNumberIntType
, &ids
[i
]);
264 CFStringRef value
= CFStringCreateWithCharacters(NULL
, (UniChar
*)str
, len
);
266 CFDictionarySetValue(dict
, key
, value
);
268 ERR("Failed to add string ID 0x%04x %s\n", ids
[i
], debugstr_wn(str
, len
));
271 ERR("Failed to load string ID 0x%04x\n", ids
[i
]);
274 localized_strings
= dict
;
278 /***********************************************************************
281 static BOOL
process_attach(void)
283 SessionAttributeBits attributes
;
286 status
= SessionGetInfo(callerSecuritySession
, NULL
, &attributes
);
287 if (status
!= noErr
|| !(attributes
& sessionHasGraphicAccess
))
291 load_strings(macdrv_module
);
293 if ((thread_data_tls_index
= TlsAlloc()) == TLS_OUT_OF_INDEXES
) return FALSE
;
295 macdrv_err_on
= ERR_ON(macdrv
);
296 if (macdrv_start_cocoa_app(GetTickCount64()))
298 ERR("Failed to start Cocoa app main loop\n");
306 /***********************************************************************
307 * ThreadDetach (MACDRV.@)
309 void CDECL
macdrv_ThreadDetach(void)
311 struct macdrv_thread_data
*data
= macdrv_thread_data();
315 macdrv_destroy_event_queue(data
->queue
);
316 if (data
->keyboard_layout_uchr
)
317 CFRelease(data
->keyboard_layout_uchr
);
318 HeapFree(GetProcessHeap(), 0, data
);
319 /* clear data in case we get re-entered from user32 before the thread is truly dead */
320 TlsSetValue(thread_data_tls_index
, NULL
);
325 /***********************************************************************
326 * set_queue_display_fd
328 * Store the event queue fd into the message queue
330 static void set_queue_display_fd(int fd
)
335 if (wine_server_fd_to_handle(fd
, GENERIC_READ
| SYNCHRONIZE
, 0, &handle
))
337 MESSAGE("macdrv: Can't allocate handle for event queue fd\n");
340 SERVER_START_REQ(set_queue_fd
)
342 req
->handle
= wine_server_obj_handle(handle
);
343 ret
= wine_server_call(req
);
348 MESSAGE("macdrv: Can't store handle for event queue fd\n");
355 /***********************************************************************
356 * macdrv_init_thread_data
358 struct macdrv_thread_data
*macdrv_init_thread_data(void)
360 struct macdrv_thread_data
*data
= macdrv_thread_data();
361 TISInputSourceRef input_source
;
363 if (data
) return data
;
365 if (!(data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
))))
367 ERR("could not create data\n");
371 if (!(data
->queue
= macdrv_create_event_queue(macdrv_handle_event
)))
373 ERR("macdrv: Can't create event queue.\n");
377 macdrv_get_input_source_info(&data
->keyboard_layout_uchr
, &data
->keyboard_type
, &data
->iso_keyboard
, &input_source
);
378 data
->active_keyboard_layout
= macdrv_get_hkl_from_source(input_source
);
379 CFRelease(input_source
);
380 macdrv_compute_keyboard_layout(data
);
382 set_queue_display_fd(macdrv_get_event_queue_fd(data
->queue
));
383 TlsSetValue(thread_data_tls_index
, data
);
389 /***********************************************************************
392 BOOL WINAPI
DllMain(HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
398 case DLL_PROCESS_ATTACH
:
399 DisableThreadLibraryCalls( hinst
);
400 macdrv_module
= hinst
;
401 ret
= process_attach();
407 /***********************************************************************
408 * SystemParametersInfo (MACDRV.@)
410 BOOL CDECL
macdrv_SystemParametersInfo( UINT action
, UINT int_param
, void *ptr_param
, UINT flags
)
414 case SPI_GETSCREENSAVEACTIVE
:
417 CFDictionaryRef assertionStates
;
418 IOReturn status
= IOPMCopyAssertionsStatus(&assertionStates
);
419 if (status
== kIOReturnSuccess
)
421 CFNumberRef count
= CFDictionaryGetValue(assertionStates
, kIOPMAssertionTypeNoDisplaySleep
);
422 CFNumberRef count2
= CFDictionaryGetValue(assertionStates
, kIOPMAssertionTypePreventUserIdleDisplaySleep
);
423 long longCount
= 0, longCount2
= 0;
426 CFNumberGetValue(count
, kCFNumberLongType
, &longCount
);
428 CFNumberGetValue(count2
, kCFNumberLongType
, &longCount2
);
430 *(BOOL
*)ptr_param
= !longCount
&& !longCount2
;
431 CFRelease(assertionStates
);
435 WARN("Could not determine screen saver state, error code %d\n", status
);
436 *(BOOL
*)ptr_param
= TRUE
;
442 case SPI_SETSCREENSAVEACTIVE
:
444 static IOPMAssertionID powerAssertion
= kIOPMNullAssertionID
;
447 if (powerAssertion
!= kIOPMNullAssertionID
)
449 IOPMAssertionRelease(powerAssertion
);
450 powerAssertion
= kIOPMNullAssertionID
;
453 else if (powerAssertion
== kIOPMNullAssertionID
)
455 CFStringRef assertName
;
456 /*Are we running Lion or later?*/
457 if (kCFCoreFoundationVersionNumber
>= kCFCoreFoundationVersionNumber10_7
)
458 assertName
= kIOPMAssertionTypePreventUserIdleDisplaySleep
;
460 assertName
= kIOPMAssertionTypeNoDisplaySleep
;
461 IOPMAssertionCreateWithName( assertName
, kIOPMAssertionLevelOn
,
462 CFSTR("Wine Process requesting no screen saver"),