mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / winemac.drv / macdrv_main.c
blob694a46b11e6493493e0cdfb18073dea32000c577
1 /*
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
22 #include "config.h"
24 #include <Security/AuthSession.h>
25 #include <IOKit/pwr_mgt/IOPMLib.h>
27 #include "macdrv.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "wine/server.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
34 #ifndef kIOPMAssertionTypePreventUserIdleDisplaySleep
35 #define kIOPMAssertionTypePreventUserIdleDisplaySleep CFSTR("PreventUserIdleDisplaySleep")
36 #endif
37 #ifndef kCFCoreFoundationVersionNumber10_7
38 #define kCFCoreFoundationVersionNumber10_7 635.00
39 #endif
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 /**************************************************************************
71 * debugstr_cf
73 const char* debugstr_cf(CFTypeRef t)
75 CFStringRef s;
76 const char* ret;
78 if (!t) return "(null)";
80 if (CFGetTypeID(t) == CFStringGetTypeID())
81 s = t;
82 else
83 s = CFCopyDescription(t);
84 ret = CFStringGetCStringPtr(s, kCFStringEncodingUTF8);
85 if (ret) ret = debugstr_a(ret);
86 if (!ret)
88 const UniChar* u = CFStringGetCharactersPtr(s);
89 if (u)
90 ret = debugstr_wn((const WCHAR*)u, CFStringGetLength(s));
92 if (!ret)
94 UniChar buf[200];
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);
100 return ret;
104 /***********************************************************************
105 * get_config_key
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 /***********************************************************************
119 * setup_options
121 * Set up the Mac driver options.
123 static void setup_options(void)
125 char buffer[MAX_PATH + 16];
126 HKEY hkey, appkey = 0;
127 DWORD len;
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)
137 HKEY tmpkey;
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;
146 RegCloseKey(tmpkey);
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;
156 else
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;
209 else
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 /***********************************************************************
227 * load_strings
229 static void load_strings(HINSTANCE instance)
231 static const unsigned int ids[] = {
232 STRING_MENU_WINE,
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,
240 STRING_MENU_WINDOW,
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;
247 int i;
249 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
250 &kCFTypeDictionaryValueCallBacks);
251 if (!dict)
253 ERR("Failed to create localized strings dictionary\n");
254 return;
257 for (i = 0; i < ARRAY_SIZE(ids); i++)
259 LPCWSTR str;
260 int len = LoadStringW(instance, ids[i], (LPWSTR)&str, 0);
261 if (str && len)
263 CFNumberRef key = CFNumberCreate(NULL, kCFNumberIntType, &ids[i]);
264 CFStringRef value = CFStringCreateWithCharacters(NULL, (UniChar*)str, len);
265 if (key && value)
266 CFDictionarySetValue(dict, key, value);
267 else
268 ERR("Failed to add string ID 0x%04x %s\n", ids[i], debugstr_wn(str, len));
270 else
271 ERR("Failed to load string ID 0x%04x\n", ids[i]);
274 localized_strings = dict;
278 /***********************************************************************
279 * process_attach
281 static BOOL process_attach(void)
283 SessionAttributeBits attributes;
284 OSStatus status;
286 status = SessionGetInfo(callerSecuritySession, NULL, &attributes);
287 if (status != noErr || !(attributes & sessionHasGraphicAccess))
288 return FALSE;
290 setup_options();
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");
299 return FALSE;
302 macdrv_init_display_devices(FALSE);
304 return TRUE;
308 /***********************************************************************
309 * ThreadDetach (MACDRV.@)
311 void CDECL macdrv_ThreadDetach(void)
313 struct macdrv_thread_data *data = macdrv_thread_data();
315 if (data)
317 macdrv_destroy_event_queue(data->queue);
318 if (data->keyboard_layout_uchr)
319 CFRelease(data->keyboard_layout_uchr);
320 HeapFree(GetProcessHeap(), 0, data);
321 /* clear data in case we get re-entered from user32 before the thread is truly dead */
322 TlsSetValue(thread_data_tls_index, NULL);
327 /***********************************************************************
328 * set_queue_display_fd
330 * Store the event queue fd into the message queue
332 static void set_queue_display_fd(int fd)
334 HANDLE handle;
335 int ret;
337 if (wine_server_fd_to_handle(fd, GENERIC_READ | SYNCHRONIZE, 0, &handle))
339 MESSAGE("macdrv: Can't allocate handle for event queue fd\n");
340 ExitProcess(1);
342 SERVER_START_REQ(set_queue_fd)
344 req->handle = wine_server_obj_handle(handle);
345 ret = wine_server_call(req);
347 SERVER_END_REQ;
348 if (ret)
350 MESSAGE("macdrv: Can't store handle for event queue fd\n");
351 ExitProcess(1);
353 CloseHandle(handle);
357 /***********************************************************************
358 * macdrv_init_thread_data
360 struct macdrv_thread_data *macdrv_init_thread_data(void)
362 struct macdrv_thread_data *data = macdrv_thread_data();
363 TISInputSourceRef input_source;
365 if (data) return data;
367 if (!(data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
369 ERR("could not create data\n");
370 ExitProcess(1);
373 if (!(data->queue = macdrv_create_event_queue(macdrv_handle_event)))
375 ERR("macdrv: Can't create event queue.\n");
376 ExitProcess(1);
379 macdrv_get_input_source_info(&data->keyboard_layout_uchr, &data->keyboard_type, &data->iso_keyboard, &input_source);
380 data->active_keyboard_layout = macdrv_get_hkl_from_source(input_source);
381 CFRelease(input_source);
382 macdrv_compute_keyboard_layout(data);
384 set_queue_display_fd(macdrv_get_event_queue_fd(data->queue));
385 TlsSetValue(thread_data_tls_index, data);
387 return data;
391 /***********************************************************************
392 * DllMain
394 BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
396 BOOL ret = TRUE;
398 switch(reason)
400 case DLL_PROCESS_ATTACH:
401 DisableThreadLibraryCalls( hinst );
402 macdrv_module = hinst;
403 ret = process_attach();
404 break;
406 return ret;
409 /***********************************************************************
410 * SystemParametersInfo (MACDRV.@)
412 BOOL CDECL macdrv_SystemParametersInfo( UINT action, UINT int_param, void *ptr_param, UINT flags )
414 switch (action)
416 case SPI_GETSCREENSAVEACTIVE:
417 if (ptr_param)
419 CFDictionaryRef assertionStates;
420 IOReturn status = IOPMCopyAssertionsStatus(&assertionStates);
421 if (status == kIOReturnSuccess)
423 CFNumberRef count = CFDictionaryGetValue(assertionStates, kIOPMAssertionTypeNoDisplaySleep);
424 CFNumberRef count2 = CFDictionaryGetValue(assertionStates, kIOPMAssertionTypePreventUserIdleDisplaySleep);
425 long longCount = 0, longCount2 = 0;
427 if (count)
428 CFNumberGetValue(count, kCFNumberLongType, &longCount);
429 if (count2)
430 CFNumberGetValue(count2, kCFNumberLongType, &longCount2);
432 *(BOOL *)ptr_param = !longCount && !longCount2;
433 CFRelease(assertionStates);
435 else
437 WARN("Could not determine screen saver state, error code %d\n", status);
438 *(BOOL *)ptr_param = TRUE;
440 return TRUE;
442 break;
444 case SPI_SETSCREENSAVEACTIVE:
446 static IOPMAssertionID powerAssertion = kIOPMNullAssertionID;
447 if (int_param)
449 if (powerAssertion != kIOPMNullAssertionID)
451 IOPMAssertionRelease(powerAssertion);
452 powerAssertion = kIOPMNullAssertionID;
455 else if (powerAssertion == kIOPMNullAssertionID)
457 CFStringRef assertName;
458 /*Are we running Lion or later?*/
459 if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_7)
460 assertName = kIOPMAssertionTypePreventUserIdleDisplaySleep;
461 else
462 assertName = kIOPMAssertionTypeNoDisplaySleep;
463 IOPMAssertionCreateWithName( assertName, kIOPMAssertionLevelOn,
464 CFSTR("Wine Process requesting no screen saver"),
465 &powerAssertion);
468 break;
470 return FALSE;