Added server-side infrastructure for the thread input structure.
Reimplemented AttachThreadInput() and added GetGUIThreadInfo().
diff --git a/server/protocol.def b/server/protocol.def
index 1aeb6c4..43f4fa0 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1908,3 +1908,26 @@
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
diff --git a/server/queue.c b/server/queue.c
index e250fae..5a08668 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -89,6 +89,19 @@
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 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 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 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 @@
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 @@
if (!thread->process->queue)
thread->process->queue = (struct msg_queue *)grab_object( queue );
}
+ release_object( input );
return queue;
}
@@ -217,7 +279,7 @@
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 @@
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 @@
msg = next;
}
}
+
+ thread_input_cleanup_window( queue, win );
}
/* post a message to a window; used by socket handling */
@@ -1098,3 +1230,65 @@
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 );
+}
diff --git a/server/request.h b/server/request.h
index 0c744b4..3f1a036 100644
--- a/server/request.h
+++ b/server/request.h
@@ -259,6 +259,8 @@
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 @@
(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 */
diff --git a/server/trace.c b/server/trace.c
index 18cda73..776370f 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2175,6 +2175,31 @@
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 @@
(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 @@
(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 @@
"remove_window_property",
"get_window_property",
"get_window_properties",
+ "attach_thread_input",
+ "get_thread_input",
};
/* ### make_requests end ### */
diff --git a/server/user.h b/server/user.h
index 6d5766e..b1cc439 100644
--- a/server/user.h
+++ b/server/user.h
@@ -46,6 +46,7 @@
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 );
diff --git a/server/window.c b/server/window.c
index e513b87..ad51288 100644
--- a/server/window.c
+++ b/server/window.c
@@ -287,6 +287,9 @@
}
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;
}