wine/dlls/winemac.drv/macdrv_main.c
Ken Thomases 451915100a winemac: Add the ability to disable high-resolution scrolling.
The Mac driver can generate scroll wheel events with values which are not integral
multiples of WHEEL_DELTA.  Apps should handle that by scrolling a corresponding
non-integral multiple of what they'd do for a WHEEL_DELTA-valued scroll or, if
they can't, then at least accumulate scroll distance until its magnitude exceeds
WHEEL_DELTA and do a "chunky" scroll.  However, many apps don't do that properly.
They may scroll way too far/fast or even in the opposite direction.

If the registry setting UsePreciseScrolling is set to "n", the Mac driver will do
that accumulation and chunking itself to work around such broken app behavior.
2014-05-15 11:28:52 +02:00

386 lines
12 KiB
C

/*
* MACDRV initialization code
*
* Copyright 1998 Patrik Stridvall
* Copyright 2000 Alexandre Julliard
* Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <Security/AuthSession.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include "macdrv.h"
#include "winuser.h"
#include "winreg.h"
#include "wine/server.h"
WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
#ifndef kIOPMAssertionTypePreventUserIdleDisplaySleep
#define kIOPMAssertionTypePreventUserIdleDisplaySleep CFSTR("PreventUserIdleDisplaySleep")
#endif
#ifndef kCFCoreFoundationVersionNumber10_7
#define kCFCoreFoundationVersionNumber10_7 635.00
#endif
#define IS_OPTION_TRUE(ch) \
((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
C_ASSERT(NUM_EVENT_TYPES <= sizeof(macdrv_event_mask) * 8);
DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES;
int topmost_float_inactive = TOPMOST_FLOAT_INACTIVE_NONFULLSCREEN;
int capture_displays_for_fullscreen = 0;
BOOL skip_single_buffer_flushes = FALSE;
BOOL allow_vsync = TRUE;
BOOL allow_set_gamma = TRUE;
int left_option_is_alt = 0;
int right_option_is_alt = 0;
BOOL allow_software_rendering = FALSE;
BOOL disable_window_decorations = FALSE;
int allow_immovable_windows = TRUE;
int cursor_clipping_locks_windows = TRUE;
int use_precise_scrolling = TRUE;
HMODULE macdrv_module = 0;
/**************************************************************************
* debugstr_cf
*/
const char* debugstr_cf(CFTypeRef t)
{
CFStringRef s;
const char* ret;
if (!t) return "(null)";
if (CFGetTypeID(t) == CFStringGetTypeID())
s = t;
else
s = CFCopyDescription(t);
ret = CFStringGetCStringPtr(s, kCFStringEncodingUTF8);
if (ret) ret = debugstr_a(ret);
if (!ret)
{
const UniChar* u = CFStringGetCharactersPtr(s);
if (u)
ret = debugstr_wn((const WCHAR*)u, CFStringGetLength(s));
}
if (!ret)
{
UniChar buf[200];
int len = min(CFStringGetLength(s), sizeof(buf)/sizeof(buf[0]));
CFStringGetCharacters(s, CFRangeMake(0, len), buf);
ret = debugstr_wn(buf, len);
}
if (s != t) CFRelease(s);
return ret;
}
/***********************************************************************
* get_config_key
*
* Get a config key from either the app-specific or the default config
*/
static inline DWORD get_config_key(HKEY defkey, HKEY appkey, const char *name,
char *buffer, DWORD size)
{
if (appkey && !RegQueryValueExA(appkey, name, 0, NULL, (LPBYTE)buffer, &size)) return 0;
if (defkey && !RegQueryValueExA(defkey, name, 0, NULL, (LPBYTE)buffer, &size)) return 0;
return ERROR_FILE_NOT_FOUND;
}
/***********************************************************************
* setup_options
*
* Set up the Mac driver options.
*/
static void setup_options(void)
{
char buffer[MAX_PATH + 16];
HKEY hkey, appkey = 0;
DWORD len;
/* @@ Wine registry key: HKCU\Software\Wine\Mac Driver */
if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Mac Driver", &hkey)) hkey = 0;
/* open the app-specific key */
len = GetModuleFileNameA(0, buffer, MAX_PATH);
if (len && len < MAX_PATH)
{
HKEY tmpkey;
char *p, *appname = buffer;
if ((p = strrchr(appname, '/'))) appname = p + 1;
if ((p = strrchr(appname, '\\'))) appname = p + 1;
strcat(appname, "\\Mac Driver");
/* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Mac Driver */
if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey))
{
if (RegOpenKeyA(tmpkey, appname, &appkey)) appkey = 0;
RegCloseKey(tmpkey);
}
}
if (!get_config_key(hkey, appkey, "WindowsFloatWhenInactive", buffer, sizeof(buffer)))
{
if (!strcmp(buffer, "none"))
topmost_float_inactive = TOPMOST_FLOAT_INACTIVE_NONE;
else if (!strcmp(buffer, "all"))
topmost_float_inactive = TOPMOST_FLOAT_INACTIVE_ALL;
else
topmost_float_inactive = TOPMOST_FLOAT_INACTIVE_NONFULLSCREEN;
}
if (!get_config_key(hkey, appkey, "CaptureDisplaysForFullscreen", buffer, sizeof(buffer)))
capture_displays_for_fullscreen = IS_OPTION_TRUE(buffer[0]);
if (!get_config_key(hkey, appkey, "SkipSingleBufferFlushes", buffer, sizeof(buffer)))
skip_single_buffer_flushes = IS_OPTION_TRUE(buffer[0]);
if (!get_config_key(hkey, appkey, "AllowVerticalSync", buffer, sizeof(buffer)))
allow_vsync = IS_OPTION_TRUE(buffer[0]);
if (!get_config_key(hkey, appkey, "AllowSetGamma", buffer, sizeof(buffer)))
allow_set_gamma = IS_OPTION_TRUE(buffer[0]);
if (!get_config_key(hkey, appkey, "LeftOptionIsAlt", buffer, sizeof(buffer)))
left_option_is_alt = IS_OPTION_TRUE(buffer[0]);
if (!get_config_key(hkey, appkey, "RightOptionIsAlt", buffer, sizeof(buffer)))
right_option_is_alt = IS_OPTION_TRUE(buffer[0]);
if (!get_config_key(hkey, appkey, "AllowSoftwareRendering", buffer, sizeof(buffer)))
allow_software_rendering = IS_OPTION_TRUE(buffer[0]);
/* Value name chosen to match what's used in the X11 driver. */
if (!get_config_key(hkey, appkey, "Decorated", buffer, sizeof(buffer)))
disable_window_decorations = !IS_OPTION_TRUE(buffer[0]);
if (!get_config_key(hkey, appkey, "AllowImmovableWindows", buffer, sizeof(buffer)))
allow_immovable_windows = IS_OPTION_TRUE(buffer[0]);
if (!get_config_key(hkey, appkey, "CursorClippingLocksWindows", buffer, sizeof(buffer)))
cursor_clipping_locks_windows = IS_OPTION_TRUE(buffer[0]);
if (!get_config_key(hkey, appkey, "UsePreciseScrolling", buffer, sizeof(buffer)))
use_precise_scrolling = IS_OPTION_TRUE(buffer[0]);
if (appkey) RegCloseKey(appkey);
if (hkey) RegCloseKey(hkey);
}
/***********************************************************************
* process_attach
*/
static BOOL process_attach(void)
{
SessionAttributeBits attributes;
OSStatus status;
status = SessionGetInfo(callerSecuritySession, NULL, &attributes);
if (status != noErr || !(attributes & sessionHasGraphicAccess))
return FALSE;
setup_options();
if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
macdrv_err_on = ERR_ON(macdrv);
if (macdrv_start_cocoa_app(GetTickCount64()))
{
ERR("Failed to start Cocoa app main loop\n");
return FALSE;
}
macdrv_clipboard_process_attach();
return TRUE;
}
/***********************************************************************
* thread_detach
*/
static void thread_detach(void)
{
struct macdrv_thread_data *data = macdrv_thread_data();
if (data)
{
macdrv_destroy_event_queue(data->queue);
if (data->keyboard_layout_uchr)
CFRelease(data->keyboard_layout_uchr);
HeapFree(GetProcessHeap(), 0, data);
/* clear data in case we get re-entered from user32 before the thread is truly dead */
TlsSetValue(thread_data_tls_index, NULL);
}
}
/***********************************************************************
* set_queue_display_fd
*
* Store the event queue fd into the message queue
*/
static void set_queue_display_fd(int fd)
{
HANDLE handle;
int ret;
if (wine_server_fd_to_handle(fd, GENERIC_READ | SYNCHRONIZE, 0, &handle))
{
MESSAGE("macdrv: Can't allocate handle for event queue fd\n");
ExitProcess(1);
}
SERVER_START_REQ(set_queue_fd)
{
req->handle = wine_server_obj_handle(handle);
ret = wine_server_call(req);
}
SERVER_END_REQ;
if (ret)
{
MESSAGE("macdrv: Can't store handle for event queue fd\n");
ExitProcess(1);
}
CloseHandle(handle);
}
/***********************************************************************
* macdrv_init_thread_data
*/
struct macdrv_thread_data *macdrv_init_thread_data(void)
{
struct macdrv_thread_data *data = macdrv_thread_data();
TISInputSourceRef input_source;
if (data) return data;
if (!(data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
{
ERR("could not create data\n");
ExitProcess(1);
}
if (!(data->queue = macdrv_create_event_queue(macdrv_handle_event)))
{
ERR("macdrv: Can't create event queue.\n");
ExitProcess(1);
}
macdrv_get_input_source_info(&data->keyboard_layout_uchr, &data->keyboard_type, &data->iso_keyboard, &input_source);
data->active_keyboard_layout = macdrv_get_hkl_from_source(input_source);
CFRelease(input_source);
macdrv_compute_keyboard_layout(data);
set_queue_display_fd(macdrv_get_event_queue_fd(data->queue));
TlsSetValue(thread_data_tls_index, data);
return data;
}
/***********************************************************************
* DllMain
*/
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
BOOL ret = TRUE;
switch(reason)
{
case DLL_PROCESS_ATTACH:
macdrv_module = hinst;
ret = process_attach();
break;
case DLL_THREAD_DETACH:
thread_detach();
break;
}
return ret;
}
/***********************************************************************
* SystemParametersInfo (MACDRV.@)
*/
BOOL CDECL macdrv_SystemParametersInfo( UINT action, UINT int_param, void *ptr_param, UINT flags )
{
switch (action)
{
case SPI_GETSCREENSAVEACTIVE:
if (ptr_param)
{
CFDictionaryRef assertionStates;
IOReturn status = IOPMCopyAssertionsStatus(&assertionStates);
if (status == kIOReturnSuccess)
{
CFNumberRef count = CFDictionaryGetValue(assertionStates, kIOPMAssertionTypeNoDisplaySleep);
CFNumberRef count2 = CFDictionaryGetValue(assertionStates, kIOPMAssertionTypePreventUserIdleDisplaySleep);
long longCount = 0, longCount2 = 0;
if (count)
CFNumberGetValue(count, kCFNumberLongType, &longCount);
if (count2)
CFNumberGetValue(count2, kCFNumberLongType, &longCount2);
*(BOOL *)ptr_param = !longCount && !longCount2;
CFRelease(assertionStates);
}
else
{
WARN("Could not determine screen saver state, error code %d\n", status);
*(BOOL *)ptr_param = TRUE;
}
return TRUE;
}
break;
case SPI_SETSCREENSAVEACTIVE:
{
static IOPMAssertionID powerAssertion = kIOPMNullAssertionID;
if (int_param)
{
if (powerAssertion != kIOPMNullAssertionID)
{
IOPMAssertionRelease(powerAssertion);
powerAssertion = kIOPMNullAssertionID;
}
}
else if (powerAssertion == kIOPMNullAssertionID)
{
CFStringRef assertName;
/*Are we running Lion or later?*/
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_7)
assertName = kIOPMAssertionTypePreventUserIdleDisplaySleep;
else
assertName = kIOPMAssertionTypeNoDisplaySleep;
IOPMAssertionCreateWithName( assertName, kIOPMAssertionLevelOn,
CFSTR("Wine Process requesting no screen saver"),
&powerAssertion);
}
}
break;
}
return FALSE;
}