Commit ab5063b2 authored by Alexandre Julliard's avatar Alexandre Julliard

Added server-side infrastructure for the thread input structure.

Reimplemented AttachThreadInput() and added GetGUIThreadInfo().
parent ed29ffde
......@@ -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
......@@ -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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment