Added server-side infrastructure for the thread input structure.
Reimplemented AttachThreadInput() and added GetGUIThreadInfo().
This commit is contained in:
parent
ed29ffdea4
commit
ab5063b217
|
@ -2231,3 +2231,58 @@ BOOL WINAPI SetMessageQueue( INT size )
|
|||
/* now obsolete the message queue will be expanded dynamically as necessary */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* AttachThreadInput (USER32.@)
|
||||
*
|
||||
* Attaches the input processing mechanism of one thread to that of
|
||||
* another thread.
|
||||
*/
|
||||
BOOL WINAPI AttachThreadInput( DWORD from, DWORD to, BOOL attach )
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
SERVER_START_REQ( attach_thread_input )
|
||||
{
|
||||
req->tid_from = from;
|
||||
req->tid_to = to;
|
||||
req->attach = attach;
|
||||
ret = !wine_server_call_err( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* GetGUIThreadInfo (USER32.@)
|
||||
*/
|
||||
BOOL WINAPI GetGUIThreadInfo( DWORD id, GUITHREADINFO *info )
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
SERVER_START_REQ( get_thread_input )
|
||||
{
|
||||
req->tid = id;
|
||||
if ((ret = !wine_server_call_err( req )))
|
||||
{
|
||||
info->flags = 0;
|
||||
info->hwndActive = reply->active;
|
||||
info->hwndFocus = reply->focus;
|
||||
info->hwndCapture = reply->capture;
|
||||
info->hwndMenuOwner = reply->menu_owner;
|
||||
info->hwndMoveSize = reply->move_size;
|
||||
info->hwndCaret = reply->caret;
|
||||
info->rcCaret.left = reply->rect.left;
|
||||
info->rcCaret.top = reply->rect.top;
|
||||
info->rcCaret.right = reply->rect.right;
|
||||
info->rcCaret.bottom = reply->rect.bottom;
|
||||
if (reply->menu_owner) info->flags |= GUI_INMENUMODE;
|
||||
if (reply->move_size) info->flags |= GUI_INMOVESIZE;
|
||||
if (reply->caret) info->flags |= GUI_CARETBLINKING;
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -244,6 +244,7 @@ init UserClientDllInitialize
|
|||
@ stdcall GetDoubleClickTime() GetDoubleClickTime
|
||||
@ stdcall GetFocus() GetFocus
|
||||
@ stdcall GetForegroundWindow() GetForegroundWindow
|
||||
@ stdcall GetGUIThreadInfo(long ptr) GetGUIThreadInfo
|
||||
@ stdcall GetIconInfo(long ptr) GetIconInfo
|
||||
@ stub GetInputDesktop
|
||||
@ stdcall GetInputState() GetInputState
|
||||
|
|
|
@ -2729,6 +2729,40 @@ struct get_window_properties_reply
|
|||
};
|
||||
|
||||
|
||||
|
||||
struct attach_thread_input_request
|
||||
{
|
||||
struct request_header __header;
|
||||
thread_id_t tid_from;
|
||||
thread_id_t tid_to;
|
||||
int attach;
|
||||
};
|
||||
struct attach_thread_input_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct get_thread_input_request
|
||||
{
|
||||
struct request_header __header;
|
||||
thread_id_t tid;
|
||||
};
|
||||
struct get_thread_input_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
user_handle_t focus;
|
||||
user_handle_t capture;
|
||||
user_handle_t active;
|
||||
user_handle_t foreground;
|
||||
user_handle_t menu_owner;
|
||||
user_handle_t move_size;
|
||||
user_handle_t caret;
|
||||
rectangle_t rect;
|
||||
};
|
||||
|
||||
|
||||
enum request
|
||||
{
|
||||
REQ_new_process,
|
||||
|
@ -2887,6 +2921,8 @@ enum request
|
|||
REQ_remove_window_property,
|
||||
REQ_get_window_property,
|
||||
REQ_get_window_properties,
|
||||
REQ_attach_thread_input,
|
||||
REQ_get_thread_input,
|
||||
REQ_NB_REQUESTS
|
||||
};
|
||||
|
||||
|
@ -3050,6 +3086,8 @@ union generic_request
|
|||
struct remove_window_property_request remove_window_property_request;
|
||||
struct get_window_property_request get_window_property_request;
|
||||
struct get_window_properties_request get_window_properties_request;
|
||||
struct attach_thread_input_request attach_thread_input_request;
|
||||
struct get_thread_input_request get_thread_input_request;
|
||||
};
|
||||
union generic_reply
|
||||
{
|
||||
|
@ -3211,8 +3249,10 @@ union generic_reply
|
|||
struct remove_window_property_reply remove_window_property_reply;
|
||||
struct get_window_property_reply get_window_property_reply;
|
||||
struct get_window_properties_reply get_window_properties_reply;
|
||||
struct attach_thread_input_reply attach_thread_input_reply;
|
||||
struct get_thread_input_reply get_thread_input_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 84
|
||||
#define SERVER_PROTOCOL_VERSION 85
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -397,6 +397,27 @@ typedef struct tagINPUT
|
|||
} INPUT, *PINPUT, *LPINPUT;
|
||||
|
||||
|
||||
typedef struct tagGUITHREADINFO
|
||||
{
|
||||
DWORD cbSize;
|
||||
DWORD flags;
|
||||
HWND hwndActive;
|
||||
HWND hwndFocus;
|
||||
HWND hwndCapture;
|
||||
HWND hwndMenuOwner;
|
||||
HWND hwndMoveSize;
|
||||
HWND hwndCaret;
|
||||
RECT rcCaret;
|
||||
} GUITHREADINFO, *PGUITHREADINFO, *LPGUITHREADINFO;
|
||||
|
||||
#define GUI_CARETBLINKING 0x00000001
|
||||
#define GUI_INMOVESIZE 0x00000002
|
||||
#define GUI_INMENUMODE 0x00000004
|
||||
#define GUI_SYSTEMMENUMODE 0x00000008
|
||||
#define GUI_POPUPMENUMODE 0x00000010
|
||||
#define GUI_16BITTASK 0x00000020
|
||||
|
||||
|
||||
/***** Dialogs *****/
|
||||
|
||||
/* Gcc on Solaris has a version of this that we don't care about */
|
||||
|
@ -4079,15 +4100,16 @@ UINT WINAPI GetDlgItemInt(HWND,INT,BOOL*,BOOL);
|
|||
INT WINAPI GetDlgItemTextA(HWND,INT,LPSTR,UINT);
|
||||
INT WINAPI GetDlgItemTextW(HWND,INT,LPWSTR,UINT);
|
||||
#define GetDlgItemText WINELIB_NAME_AW(GetDlgItemText)
|
||||
UINT WINAPI GetDoubleClickTime(void);
|
||||
HWND WINAPI GetFocus(void);
|
||||
HWND WINAPI GetForegroundWindow(void);
|
||||
BOOL WINAPI GetInputState(void);
|
||||
UINT WINAPI GetInternalWindowPos(HWND,LPRECT,LPPOINT);
|
||||
UINT WINAPI GetKBCodePage(void);
|
||||
INT WINAPI GetKeyboardType(INT);
|
||||
INT WINAPI GetKeyNameTextA(LONG,LPSTR,INT);
|
||||
INT WINAPI GetKeyNameTextW(LONG,LPWSTR,INT);
|
||||
UINT WINAPI GetDoubleClickTime(void);
|
||||
HWND WINAPI GetFocus(void);
|
||||
HWND WINAPI GetForegroundWindow(void);
|
||||
BOOL WINAPI GetGUIThreadInfo(DWORD,GUITHREADINFO*);
|
||||
BOOL WINAPI GetInputState(void);
|
||||
UINT WINAPI GetInternalWindowPos(HWND,LPRECT,LPPOINT);
|
||||
UINT WINAPI GetKBCodePage(void);
|
||||
INT WINAPI GetKeyboardType(INT);
|
||||
INT WINAPI GetKeyNameTextA(LONG,LPSTR,INT);
|
||||
INT WINAPI GetKeyNameTextW(LONG,LPWSTR,INT);
|
||||
#define GetKeyNameText WINELIB_NAME_AW(GetKeyNameText)
|
||||
INT WINAPI GetKeyboardLayoutNameA(LPSTR);
|
||||
INT WINAPI GetKeyboardLayoutNameW(LPWSTR);
|
||||
|
|
|
@ -1908,3 +1908,26 @@ enum message_type
|
|||
int total; /* total number of properties */
|
||||
VARARG(props,properties); /* list of properties */
|
||||
@END
|
||||
|
||||
|
||||
/* Attach (or detach) thread inputs */
|
||||
@REQ(attach_thread_input)
|
||||
thread_id_t tid_from; /* thread to be attached */
|
||||
thread_id_t tid_to; /* thread to which tid_from should be attached */
|
||||
int attach; /* is it an attach? */
|
||||
@END
|
||||
|
||||
|
||||
/* Get input data for a given thread */
|
||||
@REQ(get_thread_input)
|
||||
thread_id_t tid; /* id of thread */
|
||||
@REPLY
|
||||
user_handle_t focus; /* handle to the focus window */
|
||||
user_handle_t capture; /* handle to the capture window */
|
||||
user_handle_t active; /* handle to the active window */
|
||||
user_handle_t foreground; /* handle to the global foreground window */
|
||||
user_handle_t menu_owner; /* handle to the menu owner */
|
||||
user_handle_t move_size; /* handle to the moving/resizing window */
|
||||
user_handle_t caret; /* handle to the caret window */
|
||||
rectangle_t rect; /* caret rectangle */
|
||||
@END
|
||||
|
|
198
server/queue.c
198
server/queue.c
|
@ -89,6 +89,19 @@ struct timer
|
|||
unsigned int lparam; /* lparam for message */
|
||||
};
|
||||
|
||||
struct thread_input
|
||||
{
|
||||
struct object obj; /* object header */
|
||||
user_handle_t focus; /* focus window */
|
||||
user_handle_t capture; /* capture window */
|
||||
user_handle_t active; /* active window */
|
||||
user_handle_t menu_owner; /* current menu owner window */
|
||||
user_handle_t move_size; /* current moving/resizing window */
|
||||
user_handle_t caret; /* caret window */
|
||||
rectangle_t rect; /* caret rectangle */
|
||||
unsigned char keystate[256]; /* state of each key */
|
||||
};
|
||||
|
||||
struct msg_queue
|
||||
{
|
||||
struct object obj; /* object header */
|
||||
|
@ -106,6 +119,7 @@ struct msg_queue
|
|||
struct timer *last_timer; /* tail of timer list */
|
||||
struct timer *next_timer; /* next timer to expire */
|
||||
struct timeout_user *timeout; /* timeout for next timer to expire */
|
||||
struct thread_input *input; /* thread input descriptor */
|
||||
};
|
||||
|
||||
static void msg_queue_dump( struct object *obj, int verbose );
|
||||
|
@ -114,6 +128,8 @@ static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry
|
|||
static int msg_queue_signaled( struct object *obj, struct thread *thread );
|
||||
static int msg_queue_satisfied( struct object *obj, struct thread *thread );
|
||||
static void msg_queue_destroy( struct object *obj );
|
||||
static void thread_input_dump( struct object *obj, int verbose );
|
||||
static void thread_input_destroy( struct object *obj );
|
||||
static void timer_callback( void *private );
|
||||
|
||||
static const struct object_ops msg_queue_ops =
|
||||
|
@ -134,11 +150,55 @@ static const struct object_ops msg_queue_ops =
|
|||
};
|
||||
|
||||
|
||||
static struct msg_queue *create_msg_queue( struct thread *thread )
|
||||
static const struct object_ops thread_input_ops =
|
||||
{
|
||||
sizeof(struct thread_input), /* size */
|
||||
thread_input_dump, /* dump */
|
||||
no_add_queue, /* add_queue */
|
||||
NULL, /* remove_queue */
|
||||
NULL, /* signaled */
|
||||
NULL, /* satisfied */
|
||||
NULL, /* get_poll_events */
|
||||
NULL, /* poll_event */
|
||||
no_get_fd, /* get_fd */
|
||||
no_flush, /* flush */
|
||||
no_get_file_info, /* get_file_info */
|
||||
NULL, /* queue_async */
|
||||
thread_input_destroy /* destroy */
|
||||
};
|
||||
|
||||
/* create a thread input object */
|
||||
static struct thread_input *create_thread_input(void)
|
||||
{
|
||||
struct thread_input *input;
|
||||
|
||||
if ((input = alloc_object( &thread_input_ops, -1 )))
|
||||
{
|
||||
input->focus = 0;
|
||||
input->capture = 0;
|
||||
input->active = 0;
|
||||
input->menu_owner = 0;
|
||||
input->move_size = 0;
|
||||
input->caret = 0;
|
||||
input->rect.left = 0;
|
||||
input->rect.top = 0;
|
||||
input->rect.right = 0;
|
||||
input->rect.bottom = 0;
|
||||
memset( input->keystate, 0, sizeof(input->keystate) );
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
/* pointer to input structure of foreground thread */
|
||||
static struct thread_input *foreground_input;
|
||||
|
||||
/* create a message queue object */
|
||||
static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_input *input )
|
||||
{
|
||||
struct msg_queue *queue;
|
||||
int i;
|
||||
|
||||
if (!input && !(input = create_thread_input())) return NULL;
|
||||
if ((queue = alloc_object( &msg_queue_ops, -1 )))
|
||||
{
|
||||
queue->wake_bits = 0;
|
||||
|
@ -153,6 +213,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread )
|
|||
queue->last_timer = NULL;
|
||||
queue->next_timer = NULL;
|
||||
queue->timeout = NULL;
|
||||
queue->input = (struct thread_input *)grab_object( input );
|
||||
for (i = 0; i < NB_MSG_KINDS; i++)
|
||||
queue->msg_list[i].first = queue->msg_list[i].last = NULL;
|
||||
|
||||
|
@ -160,6 +221,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread )
|
|||
if (!thread->process->queue)
|
||||
thread->process->queue = (struct msg_queue *)grab_object( queue );
|
||||
}
|
||||
release_object( input );
|
||||
return queue;
|
||||
}
|
||||
|
||||
|
@ -217,7 +279,7 @@ inline static int get_hardware_msg_bit( struct message *msg )
|
|||
inline static struct msg_queue *get_current_queue(void)
|
||||
{
|
||||
struct msg_queue *queue = current->queue;
|
||||
if (!queue) queue = create_msg_queue( current );
|
||||
if (!queue) queue = create_msg_queue( current, NULL );
|
||||
return queue;
|
||||
}
|
||||
|
||||
|
@ -529,8 +591,76 @@ static void msg_queue_destroy( struct object *obj )
|
|||
timer = next;
|
||||
}
|
||||
if (queue->timeout) remove_timeout_user( queue->timeout );
|
||||
if (queue->input) release_object( queue->input );
|
||||
}
|
||||
|
||||
static void thread_input_dump( struct object *obj, int verbose )
|
||||
{
|
||||
struct thread_input *input = (struct thread_input *)obj;
|
||||
fprintf( stderr, "Thread input focus=%x capture=%x active=%x\n",
|
||||
input->focus, input->capture, input->active );
|
||||
}
|
||||
|
||||
static void thread_input_destroy( struct object *obj )
|
||||
{
|
||||
struct thread_input *input = (struct thread_input *)obj;
|
||||
|
||||
if (foreground_input == input) foreground_input = NULL;
|
||||
}
|
||||
|
||||
/* fix the thread input data when a window is destroyed */
|
||||
inline static void thread_input_cleanup_window( struct msg_queue *queue, user_handle_t window )
|
||||
{
|
||||
struct thread_input *input = queue->input;
|
||||
|
||||
if (window == input->focus) input->focus = 0;
|
||||
if (window == input->capture) input->capture = 0;
|
||||
if (window == input->active) input->active = 0;
|
||||
if (window == input->menu_owner) input->menu_owner = 0;
|
||||
if (window == input->move_size) input->move_size = 0;
|
||||
if (window == input->caret) input->caret = 0;
|
||||
}
|
||||
|
||||
/* attach two thread input data structures */
|
||||
int attach_thread_input( struct thread *thread_from, struct thread *thread_to )
|
||||
{
|
||||
struct thread_input *input;
|
||||
|
||||
if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0;
|
||||
input = (struct thread_input *)grab_object( thread_to->queue->input );
|
||||
|
||||
if (thread_from->queue)
|
||||
{
|
||||
release_object( thread_from->queue->input );
|
||||
thread_from->queue->input = input;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(thread_from->queue = create_msg_queue( thread_from, input ))) return 0;
|
||||
}
|
||||
memset( input->keystate, 0, sizeof(input->keystate) );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* detach two thread input data structures */
|
||||
static void detach_thread_input( struct thread *thread_from, struct thread *thread_to )
|
||||
{
|
||||
struct thread_input *input;
|
||||
|
||||
if (!thread_from->queue || !thread_to->queue ||
|
||||
thread_from->queue->input != thread_to->queue->input)
|
||||
{
|
||||
set_error( STATUS_ACCESS_DENIED );
|
||||
return;
|
||||
}
|
||||
if ((input = create_thread_input()))
|
||||
{
|
||||
release_object( thread_from->queue->input );
|
||||
thread_from->queue->input = input;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* set the next timer to expire */
|
||||
static void set_next_timer( struct msg_queue *queue, struct timer *timer )
|
||||
{
|
||||
|
@ -706,6 +836,8 @@ void queue_cleanup_window( struct thread *thread, user_handle_t win )
|
|||
msg = next;
|
||||
}
|
||||
}
|
||||
|
||||
thread_input_cleanup_window( queue, win );
|
||||
}
|
||||
|
||||
/* post a message to a window; used by socket handling */
|
||||
|
@ -1098,3 +1230,65 @@ DECL_HANDLER(kill_win_timer)
|
|||
if (!queue || !kill_timer( queue, get_user_full_handle(req->win), req->msg, req->id ))
|
||||
set_error( STATUS_INVALID_PARAMETER );
|
||||
}
|
||||
|
||||
|
||||
/* attach (or detach) thread inputs */
|
||||
DECL_HANDLER(attach_thread_input)
|
||||
{
|
||||
struct thread *thread_from = get_thread_from_id( req->tid_from );
|
||||
struct thread *thread_to = get_thread_from_id( req->tid_to );
|
||||
|
||||
if (!thread_from || !thread_to)
|
||||
{
|
||||
if (thread_from) release_object( thread_from );
|
||||
if (thread_to) release_object( thread_to );
|
||||
return;
|
||||
}
|
||||
if (thread_from != thread_to)
|
||||
{
|
||||
if (req->attach) attach_thread_input( thread_from, thread_to );
|
||||
else detach_thread_input( thread_from, thread_to );
|
||||
}
|
||||
else set_error( STATUS_ACCESS_DENIED );
|
||||
release_object( thread_from );
|
||||
release_object( thread_to );
|
||||
}
|
||||
|
||||
|
||||
/* get thread input data */
|
||||
DECL_HANDLER(get_thread_input)
|
||||
{
|
||||
struct thread *thread = NULL;
|
||||
struct thread_input *input;
|
||||
|
||||
if (req->tid)
|
||||
{
|
||||
if (!(thread = get_thread_from_id( req->tid ))) return;
|
||||
input = thread->queue ? thread->queue->input : NULL;
|
||||
}
|
||||
else input = foreground_input; /* get the foreground thread info */
|
||||
|
||||
if (input)
|
||||
{
|
||||
reply->focus = input->focus;
|
||||
reply->capture = input->capture;
|
||||
reply->active = input->active;
|
||||
reply->menu_owner = input->menu_owner;
|
||||
reply->move_size = input->move_size;
|
||||
reply->caret = input->caret;
|
||||
reply->rect = input->rect;
|
||||
}
|
||||
else
|
||||
{
|
||||
reply->focus = 0;
|
||||
reply->capture = 0;
|
||||
reply->active = 0;
|
||||
reply->menu_owner = 0;
|
||||
reply->move_size = 0;
|
||||
reply->caret = 0;
|
||||
reply->rect.left = reply->rect.top = reply->rect.right = reply->rect.bottom = 0;
|
||||
}
|
||||
/* foreground window is active window of foreground thread */
|
||||
reply->foreground = foreground_input ? foreground_input->active : 0;
|
||||
if (thread) release_object( thread );
|
||||
}
|
||||
|
|
|
@ -259,6 +259,8 @@ DECL_HANDLER(set_window_property);
|
|||
DECL_HANDLER(remove_window_property);
|
||||
DECL_HANDLER(get_window_property);
|
||||
DECL_HANDLER(get_window_properties);
|
||||
DECL_HANDLER(attach_thread_input);
|
||||
DECL_HANDLER(get_thread_input);
|
||||
|
||||
#ifdef WANT_REQUEST_HANDLERS
|
||||
|
||||
|
@ -421,6 +423,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_remove_window_property,
|
||||
(req_handler)req_get_window_property,
|
||||
(req_handler)req_get_window_properties,
|
||||
(req_handler)req_attach_thread_input,
|
||||
(req_handler)req_get_thread_input,
|
||||
};
|
||||
#endif /* WANT_REQUEST_HANDLERS */
|
||||
|
||||
|
|
|
@ -2175,6 +2175,31 @@ static void dump_get_window_properties_reply( const struct get_window_properties
|
|||
dump_varargs_properties( cur_size );
|
||||
}
|
||||
|
||||
static void dump_attach_thread_input_request( const struct attach_thread_input_request *req )
|
||||
{
|
||||
fprintf( stderr, " tid_from=%08x,", req->tid_from );
|
||||
fprintf( stderr, " tid_to=%08x,", req->tid_to );
|
||||
fprintf( stderr, " attach=%d", req->attach );
|
||||
}
|
||||
|
||||
static void dump_get_thread_input_request( const struct get_thread_input_request *req )
|
||||
{
|
||||
fprintf( stderr, " tid=%08x", req->tid );
|
||||
}
|
||||
|
||||
static void dump_get_thread_input_reply( const struct get_thread_input_reply *req )
|
||||
{
|
||||
fprintf( stderr, " focus=%08x,", req->focus );
|
||||
fprintf( stderr, " capture=%08x,", req->capture );
|
||||
fprintf( stderr, " active=%08x,", req->active );
|
||||
fprintf( stderr, " foreground=%08x,", req->foreground );
|
||||
fprintf( stderr, " menu_owner=%08x,", req->menu_owner );
|
||||
fprintf( stderr, " move_size=%08x,", req->move_size );
|
||||
fprintf( stderr, " caret=%08x,", req->caret );
|
||||
fprintf( stderr, " rect=" );
|
||||
dump_rectangle( &req->rect );
|
||||
}
|
||||
|
||||
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||
(dump_func)dump_new_process_request,
|
||||
(dump_func)dump_get_new_process_info_request,
|
||||
|
@ -2332,6 +2357,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_remove_window_property_request,
|
||||
(dump_func)dump_get_window_property_request,
|
||||
(dump_func)dump_get_window_properties_request,
|
||||
(dump_func)dump_attach_thread_input_request,
|
||||
(dump_func)dump_get_thread_input_request,
|
||||
};
|
||||
|
||||
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
||||
|
@ -2491,6 +2518,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_remove_window_property_reply,
|
||||
(dump_func)dump_get_window_property_reply,
|
||||
(dump_func)dump_get_window_properties_reply,
|
||||
(dump_func)0,
|
||||
(dump_func)dump_get_thread_input_reply,
|
||||
};
|
||||
|
||||
static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||
|
@ -2650,6 +2679,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"remove_window_property",
|
||||
"get_window_property",
|
||||
"get_window_properties",
|
||||
"attach_thread_input",
|
||||
"get_thread_input",
|
||||
};
|
||||
|
||||
/* ### make_requests end ### */
|
||||
|
|
|
@ -46,6 +46,7 @@ extern void *next_user_handle( user_handle_t *handle, enum user_object type );
|
|||
extern void free_msg_queue( struct thread *thread );
|
||||
extern void inc_queue_paint_count( struct thread *thread, int incr );
|
||||
extern void queue_cleanup_window( struct thread *thread, user_handle_t win );
|
||||
extern int attach_thread_input( struct thread *thread_from, struct thread *thread_to );
|
||||
extern void post_message( user_handle_t win, unsigned int message,
|
||||
unsigned int wparam, unsigned int lparam );
|
||||
|
||||
|
|
|
@ -287,6 +287,9 @@ static struct window *create_window( struct window *parent, struct window *owner
|
|||
}
|
||||
else win->next = win->prev = NULL;
|
||||
|
||||
/* if parent belongs to a different thread, attach the two threads */
|
||||
if (parent && parent->thread && parent->thread != current)
|
||||
attach_thread_input( current, parent->thread );
|
||||
return win;
|
||||
}
|
||||
|
||||
|
|
|
@ -593,88 +593,3 @@ LONG WINAPI GetMessageExtraInfo(void)
|
|||
if (!(queue = QUEUE_Current())) return 0;
|
||||
return queue->GetMessageExtraInfoVal;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* AttachThreadInput (USER32.@) Attaches input of 1 thread to other
|
||||
*
|
||||
* Attaches the input processing mechanism of one thread to that of
|
||||
* another thread.
|
||||
*
|
||||
* RETURNS
|
||||
* Success: TRUE
|
||||
* Failure: FALSE
|
||||
*
|
||||
* TODO:
|
||||
* 1. Reset the Key State (currenly per thread key state is not maintained)
|
||||
*/
|
||||
BOOL WINAPI AttachThreadInput(
|
||||
DWORD idAttach, /* [in] Thread to attach */
|
||||
DWORD idAttachTo, /* [in] Thread to attach to */
|
||||
BOOL fAttach) /* [in] Attach or detach */
|
||||
{
|
||||
MESSAGEQUEUE *pSrcMsgQ = 0, *pTgtMsgQ = 0;
|
||||
BOOL16 bRet = 0;
|
||||
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
|
||||
/* A thread cannot attach to itself */
|
||||
if ( idAttach == idAttachTo )
|
||||
goto CLEANUP;
|
||||
|
||||
/* According to the docs this method should fail if a
|
||||
* "Journal record" hook is installed. (attaches all input queues together)
|
||||
*/
|
||||
if ( HOOK_IsHooked( WH_JOURNALRECORD ) )
|
||||
goto CLEANUP;
|
||||
|
||||
/* Retrieve message queues corresponding to the thread id's */
|
||||
pTgtMsgQ = QUEUE_Lock( GetThreadQueue16( idAttach ) );
|
||||
pSrcMsgQ = QUEUE_Lock( GetThreadQueue16( idAttachTo ) );
|
||||
|
||||
/* Ensure we have message queues and that Src and Tgt threads
|
||||
* are not system threads.
|
||||
*/
|
||||
if ( !pSrcMsgQ || !pTgtMsgQ || !pSrcMsgQ->pQData || !pTgtMsgQ->pQData )
|
||||
goto CLEANUP;
|
||||
|
||||
if (fAttach) /* Attach threads */
|
||||
{
|
||||
/* Only attach if currently detached */
|
||||
if ( pTgtMsgQ->pQData != pSrcMsgQ->pQData )
|
||||
{
|
||||
/* First release the target threads perQData */
|
||||
PERQDATA_Release( pTgtMsgQ->pQData );
|
||||
|
||||
/* Share a reference to the source threads perQDATA */
|
||||
PERQDATA_Addref( pSrcMsgQ->pQData );
|
||||
pTgtMsgQ->pQData = pSrcMsgQ->pQData;
|
||||
}
|
||||
}
|
||||
else /* Detach threads */
|
||||
{
|
||||
/* Only detach if currently attached */
|
||||
if ( pTgtMsgQ->pQData == pSrcMsgQ->pQData )
|
||||
{
|
||||
/* First release the target threads perQData */
|
||||
PERQDATA_Release( pTgtMsgQ->pQData );
|
||||
|
||||
/* Give the target thread its own private perQDATA once more */
|
||||
pTgtMsgQ->pQData = PERQDATA_CreateInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Reset the Key State */
|
||||
|
||||
bRet = 1; /* Success */
|
||||
|
||||
CLEANUP:
|
||||
|
||||
/* Unlock the queues before returning */
|
||||
if ( pSrcMsgQ )
|
||||
QUEUE_Unlock( pSrcMsgQ );
|
||||
if ( pTgtMsgQ )
|
||||
QUEUE_Unlock( pTgtMsgQ );
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue