1 /*
2 * Server-side message queues
3 *
4 * Copyright (C) 2000 Alexandre Julliard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include "ntstatus.h"
30 #define WIN32_NO_STATUS
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winternl.h"
36
37 #include "handle.h"
38 #include "file.h"
39 #include "thread.h"
40 #include "process.h"
41 #include "request.h"
42 #include "user.h"
43
44 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
45 #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
46
47 enum message_kind { SEND_MESSAGE, POST_MESSAGE };
48 #define NB_MSG_KINDS (POST_MESSAGE+1)
49
50
51 struct message_result
52 {
53 struct list sender_entry; /* entry in sender list */
54 struct message *msg; /* message the result is for */
55 struct message_result *recv_next; /* next in receiver list */
56 struct msg_queue *sender; /* sender queue */
57 struct msg_queue *receiver; /* receiver queue */
58 int replied; /* has it been replied to? */
59 unsigned int error; /* error code to pass back to sender */
60 unsigned long result; /* reply result */
61 struct message *callback_msg; /* message to queue for callback */
62 void *data; /* message reply data */
63 unsigned int data_size; /* size of message reply data */
64 struct timeout_user *timeout; /* result timeout */
65 };
66
67 struct message
68 {
69 struct list entry; /* entry in message list */
70 enum message_type type; /* message type */
71 user_handle_t win; /* window handle */
72 unsigned int msg; /* message code */
73 unsigned long wparam; /* parameters */
74 unsigned long lparam; /* parameters */
75 unsigned long info; /* extra info */
76 int x; /* x position */
77 int y; /* y position */
78 unsigned int time; /* message time */
79 void *data; /* message data for sent messages */
80 unsigned int data_size; /* size of message data */
81 unsigned int unique_id; /* unique id for nested hw message waits */
82 struct message_result *result; /* result in sender queue */
83 };
84
85 struct timer
86 {
87 struct list entry; /* entry in timer list */
88 timeout_t when; /* next expiration */
89 unsigned int rate; /* timer rate in ms */
90 user_handle_t win; /* window handle */
91 unsigned int msg; /* message to post */
92 unsigned long id; /* timer id */
93 unsigned long lparam; /* lparam for message */
94 };
95
96 struct thread_input
97 {
98 struct object obj; /* object header */
99 struct desktop *desktop; /* desktop that this thread input belongs to */
100 user_handle_t focus; /* focus window */
101 user_handle_t capture; /* capture window */
102 user_handle_t active; /* active window */
103 user_handle_t menu_owner; /* current menu owner window */
104 user_handle_t move_size; /* current moving/resizing window */
105 user_handle_t caret; /* caret window */
106 rectangle_t caret_rect; /* caret rectangle */
107 int caret_hide; /* caret hide count */
108 int caret_state; /* caret on/off state */
109 struct list msg_list; /* list of hardware messages */
110 unsigned char keystate[256]; /* state of each key */
111 };
112
113 struct msg_queue
114 {
115 struct object obj; /* object header */
116 struct fd *fd; /* optional file descriptor to poll */
117 unsigned int wake_bits; /* wakeup bits */
118 unsigned int wake_mask; /* wakeup mask */
119 unsigned int changed_bits; /* changed wakeup bits */
120 unsigned int changed_mask; /* changed wakeup mask */
121 int paint_count; /* pending paint messages count */
122 int quit_message; /* is there a pending quit message? */
123 int exit_code; /* exit code of pending quit message */
124 struct list msg_list[NB_MSG_KINDS]; /* lists of messages */
125 struct list send_result; /* stack of sent messages waiting for result */
126 struct list callback_result; /* list of callback messages waiting for result */
127 struct message_result *recv_result; /* stack of received messages waiting for result */
128 struct list pending_timers; /* list of pending timers */
129 struct list expired_timers; /* list of expired timers */
130 unsigned long next_timer_id; /* id for the next timer with a 0 window */
131 struct timeout_user *timeout; /* timeout for next timer to expire */
132 struct thread_input *input; /* thread input descriptor */
133 struct hook_table *hooks; /* hook table */
134 timeout_t last_get_msg; /* time of last get message call */
135 };
136
137 static void msg_queue_dump( struct object *obj, int verbose );
138 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry );
139 static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
140 static int msg_queue_signaled( struct object *obj, struct thread *thread );
141 static int msg_queue_satisfied( struct object *obj, struct thread *thread );
142 static void msg_queue_destroy( struct object *obj );
143 static void msg_queue_poll_event( struct fd *fd, int event );
144 static void thread_input_dump( struct object *obj, int verbose );
145 static void thread_input_destroy( struct object *obj );
146 static void timer_callback( void *private );
147
148 static const struct object_ops msg_queue_ops =
149 {
150 sizeof(struct msg_queue), /* size */
151 msg_queue_dump, /* dump */
152 no_get_type, /* get_type */
153 msg_queue_add_queue, /* add_queue */
154 msg_queue_remove_queue, /* remove_queue */
155 msg_queue_signaled, /* signaled */
156 msg_queue_satisfied, /* satisfied */
157 no_signal, /* signal */
158 no_get_fd, /* get_fd */
159 no_map_access, /* map_access */
160 default_get_sd, /* get_sd */
161 default_set_sd, /* set_sd */
162 no_lookup_name, /* lookup_name */
163 no_open_file, /* open_file */
164 no_close_handle, /* close_handle */
165 msg_queue_destroy /* destroy */
166 };
167
168 static const struct fd_ops msg_queue_fd_ops =
169 {
170 NULL, /* get_poll_events */
171 msg_queue_poll_event, /* poll_event */
172 NULL, /* flush */
173 NULL, /* get_fd_type */
174 NULL, /* ioctl */
175 NULL, /* queue_async */
176 NULL, /* reselect_async */
177 NULL /* cancel async */
178 };
179
180
181 static const struct object_ops thread_input_ops =
182 {
183 sizeof(struct thread_input), /* size */
184 thread_input_dump, /* dump */
185 no_get_type, /* get_type */
186 no_add_queue, /* add_queue */
187 NULL, /* remove_queue */
188 NULL, /* signaled */
189 NULL, /* satisfied */
190 no_signal, /* signal */
191 no_get_fd, /* get_fd */
192 no_map_access, /* map_access */
193 default_get_sd, /* get_sd */
194 default_set_sd, /* set_sd */
195 no_lookup_name, /* lookup_name */
196 no_open_file, /* open_file */
197 no_close_handle, /* close_handle */
198 thread_input_destroy /* destroy */
199 };
200
201 /* pointer to input structure of foreground thread */
202 static struct thread_input *foreground_input;
203 static unsigned int last_input_time;
204
205 static void free_message( struct message *msg );
206
207 /* set the caret window in a given thread input */
208 static void set_caret_window( struct thread_input *input, user_handle_t win )
209 {
210 if (!win || win != input->caret)
211 {
212 input->caret_rect.left = 0;
213 input->caret_rect.top = 0;
214 input->caret_rect.right = 0;
215 input->caret_rect.bottom = 0;
216 }
217 input->caret = win;
218 input->caret_hide = 1;
219 input->caret_state = 0;
220 }
221
222 /* create a thread input object */
223 static struct thread_input *create_thread_input( struct thread *thread )
224 {
225 struct thread_input *input;
226
227 if ((input = alloc_object( &thread_input_ops )))
228 {
229 input->focus = 0;
230 input->capture = 0;
231 input->active = 0;
232 input->menu_owner = 0;
233 input->move_size = 0;
234 list_init( &input->msg_list );
235 set_caret_window( input, 0 );
236 memset( input->keystate, 0, sizeof(input->keystate) );
237
238 if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ )))
239 {
240 release_object( input );
241 return NULL;
242 }
243 }
244 return input;
245 }
246
247 /* release the thread input data of a given thread */
248 static inline void release_thread_input( struct thread *thread )
249 {
250 struct thread_input *input = thread->queue->input;
251
252 if (!input) return;
253 release_object( input );
254 thread->queue->input = NULL;
255 }
256
257 /* create a message queue object */
258 static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_input *input )
259 {
260 struct msg_queue *queue;
261 int i;
262
263 if (!input && !(input = create_thread_input( thread ))) return NULL;
264 if ((queue = alloc_object( &msg_queue_ops )))
265 {
266 queue->fd = NULL;
267 queue->wake_bits = 0;
268 queue->wake_mask = 0;
269 queue->changed_bits = 0;
270 queue->changed_mask = 0;
271 queue->paint_count = 0;
272 queue->quit_message = 0;
273 queue->recv_result = NULL;
274 queue->next_timer_id = 0x7fff;
275 queue->timeout = NULL;
276 queue->input = (struct thread_input *)grab_object( input );
277 queue->hooks = NULL;
278 queue->last_get_msg = current_time;
279 list_init( &queue->send_result );
280 list_init( &queue->callback_result );
281 list_init( &queue->pending_timers );
282 list_init( &queue->expired_timers );
283 for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] );
284
285 thread->queue = queue;
286 if (!thread->process->queue)
287 thread->process->queue = (struct msg_queue *)grab_object( queue );
288 }
289 release_object( input );
290 return queue;
291 }
292
293 /* free the message queue of a thread at thread exit */
294 void free_msg_queue( struct thread *thread )
295 {
296 struct process *process = thread->process;
297
298 remove_thread_hooks( thread );
299 if (!thread->queue) return;
300 if (process->queue == thread->queue) /* is it the process main queue? */
301 {
302 release_object( process->queue );
303 process->queue = NULL;
304 if (process->idle_event)
305 {
306 set_event( process->idle_event );
307 release_object( process->idle_event );
308 process->idle_event = NULL;
309 }
310 }
311 release_object( thread->queue );
312 thread->queue = NULL;
313 }
314
315 /* get the hook table for a given thread */
316 struct hook_table *get_queue_hooks( struct thread *thread )
317 {
318 if (!thread->queue) return NULL;
319 return thread->queue->hooks;
320 }
321
322 /* set the hook table for a given thread, allocating the queue if needed */
323 void set_queue_hooks( struct thread *thread, struct hook_table *hooks )
324 {
325 struct msg_queue *queue = thread->queue;
326 if (!queue && !(queue = create_msg_queue( thread, NULL ))) return;
327 if (queue->hooks) release_object( queue->hooks );
328 queue->hooks = hooks;
329 }
330
331 /* check the queue status */
332 static inline int is_signaled( struct msg_queue *queue )
333 {
334 return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
335 }
336
337 /* set some queue bits */
338 static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits )
339 {
340 queue->wake_bits |= bits;
341 queue->changed_bits |= bits;
342 if (is_signaled( queue )) wake_up( &queue->obj, 0 );
343 }
344
345 /* clear some queue bits */
346 static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits )
347 {
348 queue->wake_bits &= ~bits;
349 queue->changed_bits &= ~bits;
350 }
351
352 /* check whether msg is a keyboard message */
353 static inline int is_keyboard_msg( struct message *msg )
354 {
355 return (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST);
356 }
357
358 /* check if message is matched by the filter */
359 static inline int check_msg_filter( unsigned int msg, unsigned int first, unsigned int last )
360 {
361 return (msg >= first && msg <= last);
362 }
363
364 /* check whether a message filter contains at least one potential hardware message */
365 static inline int filter_contains_hw_range( unsigned int first, unsigned int last )
366 {
367 /* hardware message ranges are (in numerical order):
368 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
369 * WM_KEYFIRST .. WM_KEYLAST
370 * WM_MOUSEFIRST .. WM_MOUSELAST
371 */
372 if (last < WM_NCMOUSEFIRST) return 0;
373 if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
374 if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
375 if (first > WM_MOUSELAST) return 0;
376 return 1;
377 }
378
379 /* get the QS_* bit corresponding to a given hardware message */
380 static inline int get_hardware_msg_bit( struct message *msg )
381 {
382 if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
383 if (is_keyboard_msg( msg )) return QS_KEY;
384 return QS_MOUSEBUTTON;
385 }
386
387 /* get the current thread queue, creating it if needed */
388 static inline struct msg_queue *get_current_queue(void)
389 {
390 struct msg_queue *queue = current->queue;
391 if (!queue) queue = create_msg_queue( current, NULL );
392 return queue;
393 }
394
395 /* get a (pseudo-)unique id to tag hardware messages */
396 static inline unsigned int get_unique_id(void)
397 {
398 static unsigned int id;
399 if (!++id) id = 1; /* avoid an id of 0 */
400 return id;
401 }
402
403 /* try to merge a message with the last in the list; return 1 if successful */
404 static int merge_message( struct thread_input *input, const struct message *msg )
405 {
406 struct message *prev;
407 struct list *ptr = list_tail( &input->msg_list );
408
409 if (!ptr) return 0;
410 prev = LIST_ENTRY( ptr, struct message, entry );
411 if (prev->result) return 0;
412 if (prev->win && msg->win && prev->win != msg->win) return 0;
413 if (prev->msg != msg->msg) return 0;
414 if (prev->type != msg->type) return 0;
415 /* now we can merge it */
416 prev->wparam = msg->wparam;
417 prev->lparam = msg->lparam;
418 prev->x = msg->x;
419 prev->y = msg->y;
420 prev->time = msg->time;
421 prev->info = msg->info;
422 return 1;
423 }
424
425 /* free a result structure */
426 static void free_result( struct message_result *result )
427 {
428 if (result->timeout) remove_timeout_user( result->timeout );
429 free( result->data );
430 if (result->callback_msg) free_message( result->callback_msg );
431 free( result );
432 }
433
434 /* remove the result from the sender list it is on */
435 static inline void remove_result_from_sender( struct message_result *result )
436 {
437 assert( result->sender );
438
439 list_remove( &result->sender_entry );
440 result->sender = NULL;
441 if (!result->receiver) free_result( result );
442 }
443
444 /* store the message result in the appropriate structure */
445 static void store_message_result( struct message_result *res, unsigned long result,
446 unsigned int error )
447 {
448 res->result = result;
449 res->error = error;
450 res->replied = 1;
451 if (res->timeout)
452 {
453 remove_timeout_user( res->timeout );
454 res->timeout = NULL;
455 }
456 if (res->sender)
457 {
458 if (res->callback_msg)
459 {
460 /* queue the callback message in the sender queue */
461 struct callback_msg_data *data = res->callback_msg->data;
462 data->result = result;
463 list_add_tail( &res->sender->msg_list[SEND_MESSAGE], &res->callback_msg->entry );
464 set_queue_bits( res->sender, QS_SENDMESSAGE );
465 res->callback_msg = NULL;
466 remove_result_from_sender( res );
467 }
468 else
469 {
470 /* wake sender queue if waiting on this result */
471 if (list_head(&res->sender->send_result) == &res->sender_entry)
472 set_queue_bits( res->sender, QS_SMRESULT );
473 }
474 }
475
476 }
477
478 /* free a message when deleting a queue or window */
479 static void free_message( struct message *msg )
480 {
481 struct message_result *result = msg->result;
482 if (result)
483 {
484 result->msg = NULL;
485 if (result->sender)
486 {
487 result->receiver = NULL;
488 store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ );
489 }
490 else free_result( result );
491 }
492 free( msg->data );
493 free( msg );
494 }
495
496 /* remove (and free) a message from a message list */
497 static void remove_queue_message( struct msg_queue *queue, struct message *msg,
498 enum message_kind kind )
499 {
500 list_remove( &msg->entry );
501 switch(kind)
502 {
503 case SEND_MESSAGE:
504 if (list_empty( &queue->msg_list[kind] )) clear_queue_bits( queue, QS_SENDMESSAGE );
505 break;
506 case POST_MESSAGE:
507 if (list_empty( &queue->msg_list[kind] ) && !queue->quit_message)
508 clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
509 break;
510 }
511 free_message( msg );
512 }
513
514 /* message timed out without getting a reply */
515 static void result_timeout( void *private )
516 {
517 struct message_result *result = private;
518
519 assert( !result->replied );
520
521 result->timeout = NULL;
522
523 if (result->msg) /* not received yet */
524 {
525 struct message *msg = result->msg;
526
527 result->msg = NULL;
528 msg->result = NULL;
529 remove_queue_message( result->receiver, msg, SEND_MESSAGE );
530 result->receiver = NULL;
531 if (!result->sender)
532 {
533 free_result( result );
534 return;
535 }
536 }
537
538 store_message_result( result, 0, STATUS_TIMEOUT );
539 }
540
541 /* allocate and fill a message result structure */
542 static struct message_result *alloc_message_result( struct msg_queue *send_queue,
543 struct msg_queue *recv_queue,
544 struct message *msg, timeout_t timeout )
545 {
546 struct message_result *result = mem_alloc( sizeof(*result) );
547 if (result)
548 {
549 result->msg = msg;
550 result->sender = send_queue;
551 result->receiver = recv_queue;
552 result->replied = 0;
553 result->data = NULL;
554 result->data_size = 0;
555 result->timeout = NULL;
556
557 if (msg->type == MSG_CALLBACK)
558 {
559 struct message *callback_msg = mem_alloc( sizeof(*callback_msg) );
560
561 if (!callback_msg)
562 {
563 free( result );
564 return NULL;
565 }
566 callback_msg->type = MSG_CALLBACK_RESULT;
567 callback_msg->win = msg->win;
568 callback_msg->msg = msg->msg;
569 callback_msg->wparam = 0;
570 callback_msg->lparam = 0;
571 callback_msg->time = get_tick_count();
572 callback_msg->x = 0;
573 callback_msg->y = 0;
574 callback_msg->info = 0;
575 callback_msg->result = NULL;
576 /* steal the data from the original message */
577 callback_msg->data = msg->data;
578 callback_msg->data_size = msg->data_size;
579 msg->data = NULL;
580 msg->data_size = 0;
581
582 result->callback_msg = callback_msg;
583 list_add_head( &send_queue->callback_result, &result->sender_entry );
584 }
585 else
586 {
587 result->callback_msg = NULL;
588 list_add_head( &send_queue->send_result, &result->sender_entry );
589 }
590
591 if (timeout != TIMEOUT_INFINITE)
592 result->timeout = add_timeout_user( timeout, result_timeout, result );
593 }
594 return result;
595 }
596
597 /* receive a message, removing it from the sent queue */
598 static void receive_message( struct msg_queue *queue, struct message *msg,
599 struct get_message_reply *reply )
600 {
601 struct message_result *result = msg->result;
602
603 reply->total = msg->data_size;
604 if (msg->data_size > get_reply_max_size())
605 {
606 set_error( STATUS_BUFFER_OVERFLOW );
607 return;
608 }
609 reply->type = msg->type;
610 reply->win = msg->win;
611 reply->msg = msg->msg;
612 reply->wparam = msg->wparam;
613 reply->lparam = msg->lparam;
614 reply->x = msg->x;
615 reply->y = msg->y;
616 reply->time = msg->time;
617 reply->info = msg->info;
618
619 if (msg->data) set_reply_data_ptr( msg->data, msg->data_size );
620
621 list_remove( &msg->entry );
622 /* put the result on the receiver result stack */
623 if (result)
624 {
625 result->msg = NULL;
626 result->recv_next = queue->recv_result;
627 queue->recv_result = result;
628 }
629 free( msg );
630 if (list_empty( &queue->msg_list[SEND_MESSAGE] )) clear_queue_bits( queue, QS_SENDMESSAGE );
631 }
632
633 /* set the result of the current received message */
634 static void reply_message( struct msg_queue *queue, unsigned long result,
635 unsigned int error, int remove, const void *data, data_size_t len )
636 {
637 struct message_result *res = queue->recv_result;
638
639 if (remove)
640 {
641 queue->recv_result = res->recv_next;
642 res->receiver = NULL;
643 if (!res->sender) /* no one waiting for it */
644 {
645 free_result( res );
646 return;
647 }
648 }
649 if (!res->replied)
650 {
651 if (len && (res->data = memdup( data, len ))) res->data_size = len;
652 store_message_result( res, result, error );
653 }
654 }
655
656 /* retrieve a posted message */
657 static int get_posted_message( struct msg_queue *queue, user_handle_t win,
658 unsigned int first, unsigned int last, unsigned int flags,
659 struct get_message_reply *reply )
660 {
661 struct message *msg;
662
663 /* check against the filters */
664 LIST_FOR_EACH_ENTRY( msg, &queue->msg_list[POST_MESSAGE], struct message, entry )
665 {
666 if (win && msg->win && msg->win != win && !is_child_window( win, msg->win )) continue;
667 if (!check_msg_filter( msg->msg, first, last )) continue;
668 goto found; /* found one */
669 }
670 return 0;
671
672 /* return it to the app */
673 found:
674 reply->total = msg->data_size;
675 if (msg->data_size > get_reply_max_size())
676 {
677 set_error( STATUS_BUFFER_OVERFLOW );
678 return 1;
679 }
680 reply->type = msg->type;
681 reply->win = msg->win;
682 reply->msg = msg->msg;
683 reply->wparam = msg->wparam;
684 reply->lparam = msg->lparam;
685 reply->x = msg->x;
686 reply->y = msg->y;
687 reply->time = msg->time;
688 reply->info = msg->info;
689
690 if (flags & PM_REMOVE)
691 {
692 if (msg->data)
693 {
694 set_reply_data_ptr( msg->data, msg->data_size );
695 msg->data = NULL;
696 msg->data_size = 0;
697 }
698 remove_queue_message( queue, msg, POST_MESSAGE );
699 }
700 else if (msg->data) set_reply_data( msg->data, msg->data_size );
701
702 return 1;
703 }
704
705 static int get_quit_message( struct msg_queue *queue, unsigned int flags,
706 struct get_message_reply *reply )
707 {
708 if (queue->quit_message)
709 {
710 reply->total = 0;
711 reply->type = MSG_POSTED;
712 reply->win = NULL;
713 reply->msg = WM_QUIT;
714 reply->wparam = queue->exit_code;
715 reply->lparam = 0;
716 reply->x = 0;
717 reply->y = 0;
718 reply->time = get_tick_count();
719 reply->info = 0;
720
721 if (flags & PM_REMOVE)
722 {
723 queue->quit_message = 0;
724 if (list_empty( &queue->msg_list[POST_MESSAGE] ))
725 clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
726 }
727 return 1;
728 }
729 else
730 return 0;
731 }
732
733 /* empty a message list and free all the messages */
734 static void empty_msg_list( struct list *list )
735 {
736 struct list *ptr;
737
738 while ((ptr = list_head( list )) != NULL)
739 {
740 struct message *msg = LIST_ENTRY( ptr, struct message, entry );
741 list_remove( &msg->entry );
742 free_message( msg );
743 }
744 }
745
746 /* cleanup all pending results when deleting a queue */
747 static void cleanup_results( struct msg_queue *queue )
748 {
749 struct list *entry;
750
751 while ((entry = list_head( &queue->send_result )) != NULL)
752 {
753 remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
754 }
755
756 while ((entry = list_head( &queue->callback_result )) != NULL)
757 {
758 remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
759 }
760
761 while (queue->recv_result)
762 reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
763 }
764
765 /* check if the thread owning the queue is hung (not checking for messages) */
766 static int is_queue_hung( struct msg_queue *queue )
767 {
768 struct wait_queue_entry *entry;
769
770 if (current_time - queue->last_get_msg <= 5 * TICKS_PER_SEC)
771 return 0; /* less than 5 seconds since last get message -> not hung */
772
773 LIST_FOR_EACH_ENTRY( entry, &queue->obj.wait_queue, struct wait_queue_entry, entry )
774 {
775 if (entry->thread->queue == queue)
776 return 0; /* thread is waiting on queue -> not hung */
777 }
778 return 1;
779 }
780
781 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
782 {
783 struct msg_queue *queue = (struct msg_queue *)obj;
784 struct process *process = entry->thread->process;
785
786 /* a thread can only wait on its own queue */
787 if (entry->thread->queue != queue)
788 {
789 set_error( STATUS_ACCESS_DENIED );
790 return 0;
791 }
792 /* if waiting on the main process queue, set the idle event */
793 if (process->queue == queue)
794 {
795 if (process->idle_event) set_event( process->idle_event );
796 }
797 if (queue->fd && list_empty( &obj->wait_queue )) /* first on the queue */
798 set_fd_events( queue->fd, POLLIN );
799 add_queue( obj, entry );
800 return 1;
801 }
802
803 static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *entry )
804 {
805 struct msg_queue *queue = (struct msg_queue *)obj;
806 struct process *process = entry->thread->process;
807
808 remove_queue( obj, entry );
809 if (queue->fd && list_empty( &obj->wait_queue )) /* last on the queue is gone */
810 set_fd_events( queue->fd, 0 );
811
812 assert( entry->thread->queue == queue );
813
814 /* if waiting on the main process queue, reset the idle event */
815 if (process->queue == queue)
816 {
817 if (process->idle_event) reset_event( process->idle_event );
818 }
819 }
820
821 static void msg_queue_dump( struct object *obj, int verbose )
822 {
823 struct msg_queue *queue = (struct msg_queue *)obj;
824 fprintf( stderr, "Msg queue bits=%x mask=%x\n",
825 queue->wake_bits, queue->wake_mask );
826 }
827
828 static int msg_queue_signaled( struct object *obj, struct thread *thread )
829 {
830 struct msg_queue *queue = (struct msg_queue *)obj;
831 int ret = 0;
832
833 if (queue->fd)
834 {
835 if ((ret = check_fd_events( queue->fd, POLLIN )))
836 /* stop waiting on select() if we are signaled */
837 set_fd_events( queue->fd, 0 );
838 else if (!list_empty( &obj->wait_queue ))
839 /* restart waiting on poll() if we are no longer signaled */
840 set_fd_events( queue->fd, POLLIN );
841 }
842 return ret || is_signaled( queue );
843 }
844
845 static int msg_queue_satisfied( struct object *obj, struct thread *thread )
846 {
847 struct msg_queue *queue = (struct msg_queue *)obj;
848 queue->wake_mask = 0;
849 queue->changed_mask = 0;
850 return 0; /* Not abandoned */
851 }
852
853 static void msg_queue_destroy( struct object *obj )
854 {
855 struct msg_queue *queue = (struct msg_queue *)obj;
856 struct list *ptr;
857 int i;
858
859 cleanup_results( queue );
860 for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
861
862 while ((ptr = list_head( &queue->pending_timers )))
863 {
864 struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
865 list_remove( &timer->entry );
866 free( timer );
867 }
868 while ((ptr = list_head( &queue->expired_timers )))
869 {
870 struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
871 list_remove( &timer->entry );
872 free( timer );
873 }
874 if (queue->timeout) remove_timeout_user( queue->timeout );
875 if (queue->input) release_object( queue->input );
876 if (queue->hooks) release_object( queue->hooks );
877 if (queue->fd) release_object( queue->fd );
878 }
879
880 static void msg_queue_poll_event( struct fd *fd, int event )
881 {
882 struct msg_queue *queue = get_fd_user( fd );
883 assert( queue->obj.ops == &msg_queue_ops );
884
885 if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 );
886 wake_up( &queue->obj, 0 );
887 }
888
889 static void thread_input_dump( struct object *obj, int verbose )
890 {
891 struct thread_input *input = (struct thread_input *)obj;
892 fprintf( stderr, "Thread input focus=%p capture=%p active=%p\n",
893 input->focus, input->capture, input->active );
894 }
895
896 static void thread_input_destroy( struct object *obj )
897 {
898 struct thread_input *input = (struct thread_input *)obj;
899
900 if (foreground_input == input) foreground_input = NULL;
901 empty_msg_list( &input->msg_list );
902 if (input->desktop) release_object( input->desktop );
903 }
904
905 /* fix the thread input data when a window is destroyed */
906 static inline void thread_input_cleanup_window( struct msg_queue *queue, user_handle_t window )
907 {
908 struct thread_input *input = queue->input;
909
910 if (window == input->focus) input->focus = 0;
911 if (window == input->capture) input->capture = 0;
912 if (window == input->active) input->active = 0;
913 if (window == input->menu_owner) input->menu_owner = 0;
914 if (window == input->move_size) input->move_size = 0;
915 if (window == input->caret) set_caret_window( input, 0 );
916 }
917
918 /* check if the specified window can be set in the input data of a given queue */
919 static int check_queue_input_window( struct msg_queue *queue, user_handle_t window )
920 {
921 struct thread *thread;
922 int ret = 0;
923
924 if (!window) return 1; /* we can always clear the data */
925
926 if ((thread = get_window_thread( window )))
927 {
928 ret = (queue->input == thread->queue->input);
929 if (!ret) set_error( STATUS_ACCESS_DENIED );
930 release_object( thread );
931 }
932 else set_error( STATUS_INVALID_HANDLE );
933
934 return ret;
935 }
936
937 /* make sure the specified thread has a queue */
938 int init_thread_queue( struct thread *thread )
939 {
940 if (thread->queue) return 1;
941 return (create_msg_queue( thread, NULL ) != NULL);
942 }
943
944 /* attach two thread input data structures */
945 int attach_thread_input( struct thread *thread_from, struct thread *thread_to )
946 {
947 struct desktop *desktop;
948 struct thread_input *input;
949
950 if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0;
951 if (!(desktop = get_thread_desktop( thread_from, 0 ))) return 0;
952 input = (struct thread_input *)grab_object( thread_to->queue->input );
953 if (input->desktop != desktop)
954 {
955 set_error( STATUS_ACCESS_DENIED );
956 release_object( input );
957