diff --git a/debian/changelog b/debian/changelog index e3f74aa4..4bfd9db0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -21,13 +21,14 @@ wine-staging (1.7.39) UNRELEASED; urgency=low * Added patch to improve stub for ID3DXEffectImpl_CloneEffect. * Added patch with additional tests for server-PeekMessage. * Added patch to only zero the buffer up 32767 bytes in GetTempPathW. - * Added patch to implement shared memory wineserver communication for various user32 functions. + * Added patches to implement shared memory wineserver communication for various user32 functions. * Added patch to implement combase.WindowsSubstring function. * Added patch with stub for wininet.ParseX509EncodedCertificateForListBoxEntry. * Added patch to allow to edit winecfg library override by double clicking. * Added patch to fix regression causing too dark/missing textures in several games. * Added patch to fix regression causing black screen on startup. * Added patch to implement SetupLogError[A|W] and Setup[Open|Close]Log. + * Added patches to get rid of wineserver call for GetActiveWindow, GetFocus, GetCapture. * Removed patch to avoid hardcoded values for sizeof(GUID) (accepted upstream). * Removed patches for SLGetWindowsInformationDWORD (accepted upstream). * Removed patches for _ismbckata and _mbctohira (fixed upstream). diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 0b5c5c6c..147bb5b2 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -1022,11 +1022,19 @@ if test "$enable_server_Shared_Memory" -eq 1; then if test "$enable_ntdll_Threading" -gt 1; then abort "Patchset ntdll-Threading disabled, but server-Shared_Memory depends on that." fi + if test "$enable_server_Key_State" -gt 1; then + abort "Patchset server-Key_State disabled, but server-Shared_Memory depends on that." + fi + if test "$enable_server_PeekMessage" -gt 1; then + abort "Patchset server-PeekMessage disabled, but server-Shared_Memory depends on that." + fi if test "$enable_user32_Key_State" -gt 1; then abort "Patchset user32-Key_State disabled, but server-Shared_Memory depends on that." fi enable_dinput_Events=1 enable_ntdll_Threading=1 + enable_server_Key_State=1 + enable_server_PeekMessage=1 enable_user32_Key_State=1 fi @@ -3853,9 +3861,10 @@ fi # Patchset server-Shared_Memory # | # | Modified files: -# | * dlls/ntdll/ntdll_misc.h, dlls/ntdll/server.c, dlls/ntdll/thread.c, dlls/ntdll/virtual.c, dlls/user32/input.c, -# | dlls/user32/message.c, dlls/user32/user_private.h, include/wine/server.h, include/winternl.h, server/fd.c, -# | server/file.h, server/main.c, server/mapping.c, server/protocol.def, server/queue.c, server/thread.c, server/thread.h +# | * dlls/ntdll/ntdll_misc.h, dlls/ntdll/server.c, dlls/ntdll/thread.c, dlls/ntdll/virtual.c, dlls/user32/focus.c, +# | dlls/user32/input.c, dlls/user32/message.c, dlls/user32/user_private.h, dlls/user32/winstation.c, include/wine/server.h, +# | include/winternl.h, server/fd.c, server/file.h, server/main.c, server/mapping.c, server/protocol.def, server/queue.c, +# | server/thread.c, server/thread.h # | if test "$enable_server_Shared_Memory" -eq 1; then patch_apply server-Shared_Memory/0001-ntdll-Implement-virtual_map_shared_memory.patch @@ -3864,6 +3873,9 @@ if test "$enable_server_Shared_Memory" -eq 1; then patch_apply server-Shared_Memory/0004-user32-Avoid-unnecessary-wineserver-calls-in-PeekMes.patch patch_apply server-Shared_Memory/0005-user32-Get-rid-of-wineserver-call-for-GetLastInputIn.patch patch_apply server-Shared_Memory/0006-ntdll-Only-enable-wineserver-shared-memory-communica.patch + patch_apply server-Shared_Memory/0007-user32-Move-key_state-cache-into-separate-structure.patch + patch_apply server-Shared_Memory/0008-server-Store-a-list-of-associated-queues-for-each-th.patch + patch_apply server-Shared_Memory/0009-user32-Get-rid-of-wineserver-call-for-GetActiveWindo.patch ( echo '+ { "Sebastian Lackner", "ntdll: Implement virtual_map_shared_memory.", 1 },'; echo '+ { "Michael Müller", "server: Implement support for global and local shared memory blocks based on memfd.", 1 },'; @@ -3871,6 +3883,9 @@ if test "$enable_server_Shared_Memory" -eq 1; then echo '+ { "Sebastian Lackner", "user32: Avoid unnecessary wineserver calls in PeekMessage/GetMessage.", 1 },'; echo '+ { "Michael Müller", "user32: Get rid of wineserver call for GetLastInputInfo.", 1 },'; echo '+ { "Sebastian Lackner", "ntdll: Only enable wineserver shared memory communication when a special environment variable is set.", 1 },'; + echo '+ { "Sebastian Lackner", "user32: Move key_state cache into separate structure.", 1 },'; + echo '+ { "Sebastian Lackner", "server: Store a list of associated queues for each thread input.", 1 },'; + echo '+ { "Sebastian Lackner", "user32: Get rid of wineserver call for GetActiveWindow, GetFocus, GetCapture.", 1 },'; ) >> "$patchlist" fi diff --git a/patches/server-Shared_Memory/0007-user32-Move-key_state-cache-into-separate-structure.patch b/patches/server-Shared_Memory/0007-user32-Move-key_state-cache-into-separate-structure.patch new file mode 100644 index 00000000..a116622f --- /dev/null +++ b/patches/server-Shared_Memory/0007-user32-Move-key_state-cache-into-separate-structure.patch @@ -0,0 +1,159 @@ +From 66fe18ed16b77c3f69511ea9b41e6ed729624fcd Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sat, 21 Mar 2015 08:09:03 +0100 +Subject: user32: Move key_state cache into separate structure. + +We're running soon out of TEB space, so just move other key_state related fields +into the allocated memory block. +--- + dlls/user32/input.c | 26 +++++++++++++++++--------- + dlls/user32/message.c | 9 +++++---- + dlls/user32/user_private.h | 17 ++++++++++++----- + dlls/user32/winstation.c | 3 ++- + 4 files changed, 36 insertions(+), 19 deletions(-) + +diff --git a/dlls/user32/input.c b/dlls/user32/input.c +index 2512887..8608f75 100644 +--- a/dlls/user32/input.c ++++ b/dlls/user32/input.c +@@ -376,6 +376,7 @@ void CDECL __wine_check_for_events( UINT flags ) + SHORT WINAPI DECLSPEC_HOTPATCH GetAsyncKeyState( INT key ) + { + struct user_thread_info *thread_info = get_user_thread_info(); ++ struct user_key_state_info *key_state_info = thread_info->key_state; + INT epoch = global_key_state_epoch; + SHORT ret; + +@@ -385,26 +386,33 @@ SHORT WINAPI DECLSPEC_HOTPATCH GetAsyncKeyState( INT key ) + + if ((ret = USER_Driver->pGetAsyncKeyState( key )) == -1) + { +- if (thread_info->key_state && +- !(thread_info->key_state[key] & 0xc0) && +- GetTickCount() - thread_info->key_state_time < 50 && +- thread_info->key_state_epoch == epoch) ++ if (key_state_info && !(key_state_info->key_state[key] & 0xc0) && ++ GetTickCount() - key_state_info->key_state_time < 50 && ++ key_state_info->key_state_epoch == epoch) ++ { + return 0; +- +- if (!thread_info->key_state) thread_info->key_state = HeapAlloc( GetProcessHeap(), 0, 256 ); ++ } ++ else if (!key_state_info) ++ { ++ key_state_info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*key_state_info) ); ++ if (key_state_info) thread_info->key_state = key_state_info; ++ } + + ret = 0; + SERVER_START_REQ( get_key_state ) + { + req->tid = 0; + req->key = key; +- if (thread_info->key_state) wine_server_set_reply( req, thread_info->key_state, 256 ); ++ if (key_state_info) wine_server_set_reply( req, key_state_info->key_state, sizeof(key_state_info->key_state) ); + if (!wine_server_call( req )) + { + if (reply->state & 0x40) ret |= 0x0001; + if (reply->state & 0x80) ret |= 0x8000; +- thread_info->key_state_time = GetTickCount(); +- thread_info->key_state_epoch = epoch; ++ if (key_state_info) ++ { ++ key_state_info->key_state_time = GetTickCount(); ++ key_state_info->key_state_epoch = epoch; ++ } + } + } + SERVER_END_REQ; +diff --git a/dlls/user32/message.c b/dlls/user32/message.c +index 4bc17e9..33e826e 100644 +--- a/dlls/user32/message.c ++++ b/dlls/user32/message.c +@@ -3304,6 +3304,7 @@ static BOOL send_message( struct send_message_info *info, DWORD_PTR *res_ptr, BO + NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) + { + struct user_thread_info *thread_info = get_user_thread_info(); ++ struct user_key_state_info *key_state_info = thread_info->key_state; + struct send_message_info info; + int prev_x, prev_y, new_x, new_y; + NTSTATUS ret; +@@ -3343,7 +3344,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) + req->input.hw.lparam = MAKELONG( input->u.hi.wParamL, input->u.hi.wParamH ); + break; + } +- if (thread_info->key_state) wine_server_set_reply( req, thread_info->key_state, 256 ); ++ if (key_state_info) wine_server_set_reply( req, key_state_info->key_state, sizeof(key_state_info->key_state) ); + ret = wine_server_call( req ); + wait = reply->wait; + prev_x = reply->prev_x; +@@ -3355,10 +3356,10 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) + + if (!ret) + { +- if (thread_info->key_state) ++ if (key_state_info) + { +- thread_info->key_state_time = GetTickCount(); +- thread_info->key_state_epoch = epoch; ++ key_state_info->key_state_time = GetTickCount(); ++ key_state_info->key_state_epoch = epoch; + } + if ((flags & SEND_HWMSG_INJECTED) && (prev_x != new_x || prev_y != new_y)) + USER_Driver->pSetCursorPos( new_x, new_y ); +diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h +index adf73ff..a35ebf3 100644 +--- a/dlls/user32/user_private.h ++++ b/dlls/user32/user_private.h +@@ -184,19 +184,26 @@ struct user_thread_info + DWORD GetMessageTimeVal; /* Value for GetMessageTime */ + DWORD GetMessagePosVal; /* Value for GetMessagePos */ + ULONG_PTR GetMessageExtraInfoVal; /* Value for GetMessageExtraInfo */ +- UINT active_hooks; /* Bitmap of active hooks */ +- UINT key_state_time; /* Time of last key state refresh */ +- BYTE *key_state; /* Cache of global key state */ + HWND top_window; /* Desktop window */ + HWND msg_window; /* HWND_MESSAGE parent window */ + RAWINPUT *rawinput; +- INT key_state_epoch; /* Counter to invalidate the key state */ ++ struct user_key_state_info *key_state; /* Cache of global key state */ ++ UINT active_hooks; /* Bitmap of active hooks */ + DWORD last_get_msg; /* Last message time */ + +- ULONG pad[3]; /* Available for more data */ ++ ULONG pad[5]; /* Available for more data */ + }; + #include + ++C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); ++ ++struct user_key_state_info ++{ ++ UINT key_state_time; /* Time of last key state refresh */ ++ INT key_state_epoch; /* Counter to invalidate the key state */ ++ BYTE key_state[256]; /* State for each key */ ++}; ++ + extern INT global_key_state_epoch DECLSPEC_HIDDEN; + + struct hook_extra_info +diff --git a/dlls/user32/winstation.c b/dlls/user32/winstation.c +index 12b9edc..0e8260a 100644 +--- a/dlls/user32/winstation.c ++++ b/dlls/user32/winstation.c +@@ -399,9 +399,10 @@ BOOL WINAPI SetThreadDesktop( HDESK handle ) + if (ret) /* reset the desktop windows */ + { + struct user_thread_info *thread_info = get_user_thread_info(); ++ struct user_key_state_info *key_state_info = thread_info->key_state; + thread_info->top_window = 0; + thread_info->msg_window = 0; +- thread_info->key_state_time = 0; ++ if (key_state_info) key_state_info->key_state_time = 0; + } + return ret; + } +-- +2.3.2 + diff --git a/patches/server-Shared_Memory/0008-server-Store-a-list-of-associated-queues-for-each-th.patch b/patches/server-Shared_Memory/0008-server-Store-a-list-of-associated-queues-for-each-th.patch new file mode 100644 index 00000000..5e702097 --- /dev/null +++ b/patches/server-Shared_Memory/0008-server-Store-a-list-of-associated-queues-for-each-th.patch @@ -0,0 +1,79 @@ +From 94d2d107e2a3b1b09fdeaa1fdd179d955383f89d Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sat, 21 Mar 2015 09:00:17 +0100 +Subject: server: Store a list of associated queues for each thread input. + +Required by the following patches, splitted as a separate patch for easier +reviewing. +--- + server/queue.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/server/queue.c b/server/queue.c +index 4697d15..8f60a7e 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -99,6 +99,7 @@ struct thread_input + { + struct object obj; /* object header */ + struct desktop *desktop; /* desktop that this thread input belongs to */ ++ struct list queues; /* list of all queues this input belongs to */ + user_handle_t focus; /* focus window */ + user_handle_t capture; /* capture window */ + user_handle_t active; /* active window */ +@@ -139,6 +140,7 @@ struct msg_queue + lparam_t next_timer_id; /* id for the next timer with a 0 window */ + struct timeout_user *timeout; /* timeout for next timer to expire */ + struct thread_input *input; /* thread input descriptor */ ++ struct list input_entry; /* entry in input->queues */ + struct hook_table *hooks; /* hook table */ + timeout_t last_get_msg; /* time of last get message call */ + unsigned int ignore_post_msg; /* ignore post messages newer than this unique id */ +@@ -254,6 +256,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) + input->cursor = 0; + input->cursor_count = 0; + input->lock_count = 0; ++ list_init( &input->queues ); + list_init( &input->msg_list ); + set_caret_window( input, 0 ); + memset( input->keystate, 0, sizeof(input->keystate) ); +@@ -297,6 +300,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + queue->next_timer_id = 0x7fff; + queue->timeout = NULL; + queue->input = (struct thread_input *)grab_object( input ); ++ list_add_tail( &input->queues, &queue->input_entry ); + queue->hooks = NULL; + queue->last_get_msg = current_time; + queue->ignore_post_msg = 0; +@@ -336,10 +340,12 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ + { + if (queue->keystate_locked) queue->input->lock_count--; + queue->input->cursor_count -= queue->cursor_count; ++ list_remove( &queue->input_entry ); + release_object( queue->input ); + queue->keystate_locked = 0; + } + queue->input = (struct thread_input *)grab_object( new_input ); ++ list_add_tail( &new_input->queues, &queue->input_entry ); + new_input->cursor_count += queue->cursor_count; + return 1; + } +@@ -1003,6 +1009,7 @@ static void msg_queue_destroy( struct object *obj ) + if (queue->timeout) remove_timeout_user( queue->timeout ); + if (queue->keystate_locked) queue->input->lock_count--; + queue->input->cursor_count -= queue->cursor_count; ++ list_remove( &queue->input_entry ); + release_object( queue->input ); + if (queue->hooks) release_object( queue->hooks ); + if (queue->fd) release_object( queue->fd ); +@@ -1029,6 +1036,7 @@ static void thread_input_destroy( struct object *obj ) + { + struct thread_input *input = (struct thread_input *)obj; + ++ assert( list_empty(&input->queues) ); + empty_msg_list( &input->msg_list ); + if (input->desktop) + { +-- +2.3.2 + diff --git a/patches/server-Shared_Memory/0009-user32-Get-rid-of-wineserver-call-for-GetActiveWindo.patch b/patches/server-Shared_Memory/0009-user32-Get-rid-of-wineserver-call-for-GetActiveWindo.patch new file mode 100644 index 00000000..a55cb030 --- /dev/null +++ b/patches/server-Shared_Memory/0009-user32-Get-rid-of-wineserver-call-for-GetActiveWindo.patch @@ -0,0 +1,156 @@ +From f984ad3f5502b815480cc135703e0ea843eb84a3 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sat, 21 Mar 2015 09:45:54 +0100 +Subject: user32: Get rid of wineserver call for GetActiveWindow, GetFocus, + GetCapture. + +--- + dlls/user32/focus.c | 4 ++++ + dlls/user32/input.c | 2 ++ + server/protocol.def | 5 ++++- + server/queue.c | 30 +++++++++++++++++++++++++++++- + 4 files changed, 39 insertions(+), 2 deletions(-) + +diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c +index c47a82d..35fe89b 100644 +--- a/dlls/user32/focus.c ++++ b/dlls/user32/focus.c +@@ -329,8 +329,10 @@ BOOL WINAPI SetForegroundWindow( HWND hwnd ) + */ + HWND WINAPI GetActiveWindow(void) + { ++ shmlocal_t *shm = wine_get_shmlocal(); + HWND ret = 0; + ++ if (shm) return wine_server_ptr_handle( shm->input_active ); + SERVER_START_REQ( get_thread_input ) + { + req->tid = GetCurrentThreadId(); +@@ -346,8 +348,10 @@ HWND WINAPI GetActiveWindow(void) + */ + HWND WINAPI GetFocus(void) + { ++ shmlocal_t *shm = wine_get_shmlocal(); + HWND ret = 0; + ++ if (shm) return wine_server_ptr_handle( shm->input_focus ); + SERVER_START_REQ( get_thread_input ) + { + req->tid = GetCurrentThreadId(); +diff --git a/dlls/user32/input.c b/dlls/user32/input.c +index 8608f75..e534ac1 100644 +--- a/dlls/user32/input.c ++++ b/dlls/user32/input.c +@@ -342,8 +342,10 @@ BOOL WINAPI DECLSPEC_HOTPATCH ReleaseCapture(void) + */ + HWND WINAPI GetCapture(void) + { ++ shmlocal_t *shm = wine_get_shmlocal(); + HWND ret = 0; + ++ if (shm) return wine_server_ptr_handle( shm->input_capture ); + SERVER_START_REQ( get_thread_input ) + { + req->tid = GetCurrentThreadId(); +diff --git a/server/protocol.def b/server/protocol.def +index cf6d783..7eaa6cd 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -76,7 +76,10 @@ typedef struct + + typedef struct + { +- int queue_bits; /* queue wake bits */ ++ int queue_bits; /* queue wake bits */ ++ user_handle_t input_focus; /* focus window */ ++ user_handle_t input_capture; /* capture window */ ++ user_handle_t input_active; /* active window */ + } shmlocal_t; + + /* debug event data */ +diff --git a/server/queue.c b/server/queue.c +index 0ca35d7..54611c2 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -269,6 +269,25 @@ static struct thread_input *create_thread_input( struct thread *thread ) + return input; + } + ++/* synchronize the input state with the shared memory */ ++static void update_shm_thread_input( struct thread_input *input ) ++{ ++ struct msg_queue *queue; ++ ++ /* the loop doesn't matter, usually it should only have one or a few entries */ ++ LIST_FOR_EACH_ENTRY( queue, &input->queues, struct msg_queue, input_entry ) ++ { ++ shmlocal_t *shm; ++ if (!queue->thread) return; ++ if ((shm = queue->thread->shm)) ++ { ++ shm->input_active = input->active; ++ shm->input_focus = input->focus; ++ shm->input_capture = input->capture; ++ } ++ } ++} ++ + /* create a message queue object */ + static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_input *input ) + { +@@ -310,7 +329,11 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + + thread->queue = queue; + } +- if (new_input) release_object( new_input ); ++ if (new_input) ++ { ++ update_shm_thread_input( new_input ); ++ release_object( new_input ); ++ } + return queue; + } + +@@ -345,6 +368,7 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ + queue->input = (struct thread_input *)grab_object( new_input ); + list_add_tail( &new_input->queues, &queue->input_entry ); + new_input->cursor_count += queue->cursor_count; ++ update_shm_thread_input( new_input ); + return 1; + } + +@@ -1045,6 +1069,7 @@ static inline void thread_input_cleanup_window( struct msg_queue *queue, user_ha + if (window == input->menu_owner) input->menu_owner = 0; + if (window == input->move_size) input->move_size = 0; + if (window == input->caret) set_caret_window( input, 0 ); ++ update_shm_thread_input( input ); + } + + /* check if the specified window can be set in the input data of a given queue */ +@@ -2954,6 +2979,7 @@ DECL_HANDLER(set_focus_window) + { + reply->previous = queue->input->focus; + queue->input->focus = get_user_full_handle( req->handle ); ++ update_shm_thread_input( queue->input ); + } + } + +@@ -2970,6 +2996,7 @@ DECL_HANDLER(set_active_window) + { + reply->previous = queue->input->active; + queue->input->active = get_user_full_handle( req->handle ); ++ update_shm_thread_input( queue->input ); + } + else set_error( STATUS_INVALID_HANDLE ); + } +@@ -2996,6 +3023,7 @@ DECL_HANDLER(set_capture_window) + input->capture = get_user_full_handle( req->handle ); + input->menu_owner = (req->flags & CAPTURE_MENU) ? input->capture : 0; + input->move_size = (req->flags & CAPTURE_MOVESIZE) ? input->capture : 0; ++ update_shm_thread_input( input ); + reply->full_handle = input->capture; + } + } +-- +2.3.2 + diff --git a/patches/server-Shared_Memory/definition b/patches/server-Shared_Memory/definition index fb74ab29..1c71ed97 100644 --- a/patches/server-Shared_Memory/definition +++ b/patches/server-Shared_Memory/definition @@ -1,3 +1,5 @@ Depends: ntdll-Threading Depends: user32-Key_State Depends: dinput-Events +Depends: server-Key_State +Depends: server-PeekMessage