Moved undocshell.h to dlls/shell32. Removed shell16.h.
[wine/multimedia.git] / server / queue.c
blob238e3a988584a5e1a66d17f8219764894a8865b0
1 /*
2 * Server-side message queues
4 * Copyright (C) 2000 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <stdio.h>
9 #include <stdlib.h>
11 #include "winbase.h"
12 #include "wingdi.h"
13 #include "winuser.h"
15 #include "handle.h"
16 #include "thread.h"
17 #include "process.h"
18 #include "request.h"
20 enum message_kind { SEND_MESSAGE, POST_MESSAGE, COOKED_HW_MESSAGE, RAW_HW_MESSAGE };
21 #define NB_MSG_KINDS (RAW_HW_MESSAGE+1)
24 struct message_result
26 struct message_result *send_next; /* next in sender list */
27 struct message_result *recv_next; /* next in receiver list */
28 struct msg_queue *sender; /* sender queue */
29 struct msg_queue *receiver; /* receiver queue */
30 int replied; /* has it been replied to? */
31 unsigned int result; /* reply result */
32 unsigned int error; /* error code to pass back to sender */
33 void *data; /* message reply data */
34 unsigned int data_size; /* size of message reply data */
35 struct timeout_user *timeout; /* result timeout */
38 struct message
40 struct message *next; /* next message in list */
41 struct message *prev; /* prev message in list */
42 enum message_type type; /* message type */
43 handle_t win; /* window handle */
44 unsigned int msg; /* message code */
45 unsigned int wparam; /* parameters */
46 unsigned int lparam; /* parameters */
47 int x; /* x position */
48 int y; /* y position */
49 unsigned int time; /* message time */
50 unsigned int info; /* extra info */
51 void *data; /* message data for sent messages */
52 unsigned int data_size; /* size of message data */
53 struct message_result *result; /* result in sender queue */
56 struct message_list
58 struct message *first; /* head of list */
59 struct message *last; /* tail of list */
62 struct timer
64 struct timer *next; /* next timer in list */
65 struct timer *prev; /* prev timer in list */
66 struct timeval when; /* next expiration */
67 unsigned int rate; /* timer rate in ms */
68 handle_t win; /* window handle */
69 unsigned int msg; /* message to post */
70 unsigned int id; /* timer id */
71 unsigned int lparam; /* lparam for message */
74 struct msg_queue
76 struct object obj; /* object header */
77 unsigned int wake_bits; /* wakeup bits */
78 unsigned int wake_mask; /* wakeup mask */
79 unsigned int changed_bits; /* changed wakeup bits */
80 unsigned int changed_mask; /* changed wakeup mask */
81 int paint_count; /* pending paint messages count */
82 struct message_list msg_list[NB_MSG_KINDS]; /* lists of messages */
83 struct message_result *send_result; /* stack of sent messages waiting for result */
84 struct message_result *recv_result; /* stack of received messages waiting for result */
85 struct message *last_msg; /* last msg returned to the app and not removed */
86 enum message_kind last_msg_kind; /* message kind of last_msg */
87 struct timer *first_timer; /* head of timer list */
88 struct timer *last_timer; /* tail of timer list */
89 struct timer *next_timer; /* next timer to expire */
90 struct timeout_user *timeout; /* timeout for next timer to expire */
93 static void msg_queue_dump( struct object *obj, int verbose );
94 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry );
95 static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
96 static int msg_queue_signaled( struct object *obj, struct thread *thread );
97 static int msg_queue_satisfied( struct object *obj, struct thread *thread );
98 static void msg_queue_destroy( struct object *obj );
99 static void timer_callback( void *private );
101 static const struct object_ops msg_queue_ops =
103 sizeof(struct msg_queue), /* size */
104 msg_queue_dump, /* dump */
105 msg_queue_add_queue, /* add_queue */
106 msg_queue_remove_queue, /* remove_queue */
107 msg_queue_signaled, /* signaled */
108 msg_queue_satisfied, /* satisfied */
109 NULL, /* get_poll_events */
110 NULL, /* poll_event */
111 no_get_fd, /* get_fd */
112 no_flush, /* flush */
113 no_get_file_info, /* get_file_info */
114 msg_queue_destroy /* destroy */
118 static struct msg_queue *create_msg_queue( struct thread *thread )
120 struct msg_queue *queue;
121 int i;
123 if ((queue = alloc_object( &msg_queue_ops, -1 )))
125 queue->wake_bits = 0;
126 queue->wake_mask = 0;
127 queue->changed_bits = 0;
128 queue->changed_mask = 0;
129 queue->paint_count = 0;
130 queue->send_result = NULL;
131 queue->recv_result = NULL;
132 queue->last_msg = NULL;
133 queue->first_timer = NULL;
134 queue->last_timer = NULL;
135 queue->next_timer = NULL;
136 queue->timeout = NULL;
137 for (i = 0; i < NB_MSG_KINDS; i++)
138 queue->msg_list[i].first = queue->msg_list[i].last = NULL;
140 thread->queue = queue;
141 if (!thread->process->queue)
142 thread->process->queue = (struct msg_queue *)grab_object( queue );
144 return queue;
147 /* check the queue status */
148 inline static int is_signaled( struct msg_queue *queue )
150 return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
153 /* set some queue bits */
154 inline static void set_queue_bits( struct msg_queue *queue, unsigned int bits )
156 queue->wake_bits |= bits;
157 queue->changed_bits |= bits;
158 if (is_signaled( queue )) wake_up( &queue->obj, 0 );
161 /* clear some queue bits */
162 inline static void clear_queue_bits( struct msg_queue *queue, unsigned int bits )
164 queue->wake_bits &= ~bits;
165 queue->changed_bits &= ~bits;
168 /* get the QS_* bit corresponding to a given hardware message */
169 inline static int get_hardware_msg_bit( struct message *msg )
171 if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
172 if (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST) return QS_KEY;
173 return QS_MOUSEBUTTON;
176 /* get the current thread queue, creating it if needed */
177 inline struct msg_queue *get_current_queue(void)
179 struct msg_queue *queue = current->queue;
180 if (!queue) queue = create_msg_queue( current );
181 return queue;
184 /* append a message to the end of a list */
185 inline static void append_message( struct message_list *list, struct message *msg )
187 msg->next = NULL;
188 if ((msg->prev = list->last)) msg->prev->next = msg;
189 else list->first = msg;
190 list->last = msg;
193 /* unlink a message from a list it */
194 inline static void unlink_message( struct message_list *list, struct message *msg )
196 if (msg->next) msg->next->prev = msg->prev;
197 else list->last = msg->prev;
198 if (msg->prev) msg->prev->next = msg->next;
199 else list->first = msg->next;
202 /* try to merge a message with the last in the list; return 1 if successful */
203 static int merge_message( struct message_list *list, const struct message *msg )
205 struct message *prev = list->last;
207 if (!prev) return 0;
208 if (prev->result) return 0;
209 if (prev->win != msg->win) return 0;
210 if (prev->msg != msg->msg) return 0;
211 if (prev->type != msg->type) return 0;
212 /* now we can merge it */
213 prev->wparam = msg->wparam;
214 prev->lparam = msg->lparam;
215 prev->x = msg->x;
216 prev->y = msg->y;
217 prev->time = msg->time;
218 prev->info = msg->info;
219 return 1;
222 /* free a result structure */
223 static void free_result( struct message_result *result )
225 if (result->timeout) remove_timeout_user( result->timeout );
226 if (result->data) free( result->data );
227 free( result );
230 /* store the message result in the appropriate structure */
231 static void store_message_result( struct message_result *res, unsigned int result,
232 unsigned int error )
234 res->result = result;
235 res->error = error;
236 res->replied = 1;
237 if (res->timeout)
239 remove_timeout_user( res->timeout );
240 res->timeout = NULL;
242 /* wake sender queue if waiting on this result */
243 if (res->sender && res->sender->send_result == res)
244 set_queue_bits( res->sender, QS_SMRESULT );
247 /* free a message when deleting a queue or window */
248 static void free_message( struct message *msg )
250 struct message_result *result = msg->result;
251 if (result)
253 if (result->sender)
255 result->receiver = NULL;
256 store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ );
258 else free_result( result );
260 if (msg->data) free( msg->data );
261 free( msg );
264 /* remove (and free) a message from a message list */
265 static void remove_queue_message( struct msg_queue *queue, struct message *msg,
266 enum message_kind kind )
268 int clr_bit;
269 struct message *other;
271 if (queue->last_msg == msg) queue->last_msg = NULL;
272 unlink_message( &queue->msg_list[kind], msg );
273 switch(kind)
275 case SEND_MESSAGE:
276 if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_SENDMESSAGE );
277 break;
278 case POST_MESSAGE:
279 if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_POSTMESSAGE );
280 break;
281 case COOKED_HW_MESSAGE:
282 case RAW_HW_MESSAGE:
283 clr_bit = get_hardware_msg_bit( msg );
284 for (other = queue->msg_list[kind].first; other; other = other->next)
285 if (get_hardware_msg_bit( other ) == clr_bit) break;
286 if (!other) clear_queue_bits( queue, clr_bit );
287 break;
289 free_message( msg );
292 /* message timed out without getting a reply */
293 static void result_timeout( void *private )
295 struct message_result *result = private;
297 assert( !result->replied );
299 result->timeout = NULL;
300 store_message_result( result, 0, STATUS_TIMEOUT );
303 /* allocate and fill a message result structure */
304 static struct message_result *alloc_message_result( struct msg_queue *send_queue,
305 struct msg_queue *recv_queue,
306 unsigned int timeout )
308 struct message_result *result = mem_alloc( sizeof(*result) );
309 if (result)
311 /* put the result on the sender result stack */
312 result->sender = send_queue;
313 result->receiver = recv_queue;
314 result->replied = 0;
315 result->data = NULL;
316 result->data_size = 0;
317 result->timeout = NULL;
318 result->send_next = send_queue->send_result;
319 send_queue->send_result = result;
320 if (timeout != -1)
322 struct timeval when;
323 gettimeofday( &when, 0 );
324 add_timeout( &when, timeout );
325 result->timeout = add_timeout_user( &when, result_timeout, result );
328 return result;
331 /* receive a message, removing it from the sent queue */
332 static void receive_message( struct msg_queue *queue, struct message *msg )
334 struct message_result *result = msg->result;
336 unlink_message( &queue->msg_list[SEND_MESSAGE], msg );
337 /* put the result on the receiver result stack */
338 if (result)
340 result->recv_next = queue->recv_result;
341 queue->recv_result = result;
343 if (msg->data) free( msg->data );
344 free( msg );
345 if (!queue->msg_list[SEND_MESSAGE].first) clear_queue_bits( queue, QS_SENDMESSAGE );
348 /* set the result of the current received message */
349 static void reply_message( struct msg_queue *queue, unsigned int result,
350 unsigned int error, int remove, void *data, size_t len )
352 struct message_result *res = queue->recv_result;
354 if (remove)
356 queue->recv_result = res->recv_next;
357 res->receiver = NULL;
358 if (!res->sender) /* no one waiting for it */
360 free_result( res );
361 return;
364 if (!res->replied)
366 if (len && (res->data = memdup( data, len ))) res->data_size = len;
367 store_message_result( res, result, error );
371 /* empty a message list and free all the messages */
372 static void empty_msg_list( struct message_list *list )
374 struct message *msg = list->first;
375 while (msg)
377 struct message *next = msg->next;
378 free_message( msg );
379 msg = next;
383 /* cleanup all pending results when deleting a queue */
384 static void cleanup_results( struct msg_queue *queue )
386 struct message_result *result, *next;
388 result = queue->send_result;
389 while (result)
391 next = result->send_next;
392 result->sender = NULL;
393 if (!result->receiver) free_result( result );
394 result = next;
397 while (queue->recv_result)
398 reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
401 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
403 struct msg_queue *queue = (struct msg_queue *)obj;
404 struct process *process = entry->thread->process;
406 /* a thread can only wait on its own queue */
407 if (entry->thread->queue != queue)
409 set_error( STATUS_ACCESS_DENIED );
410 return 0;
412 /* if waiting on the main process queue, set the idle event */
413 if (process->queue == queue)
415 if (process->idle_event) set_event( process->idle_event );
417 add_queue( obj, entry );
418 return 1;
421 static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *entry )
423 struct msg_queue *queue = (struct msg_queue *)obj;
424 struct process *process = entry->thread->process;
426 remove_queue( obj, entry );
428 assert( entry->thread->queue == queue );
430 /* if waiting on the main process queue, reset the idle event */
431 if (process->queue == queue)
433 if (process->idle_event) reset_event( process->idle_event );
437 static void msg_queue_dump( struct object *obj, int verbose )
439 struct msg_queue *queue = (struct msg_queue *)obj;
440 fprintf( stderr, "Msg queue bits=%x mask=%x\n",
441 queue->wake_bits, queue->wake_mask );
444 static int msg_queue_signaled( struct object *obj, struct thread *thread )
446 struct msg_queue *queue = (struct msg_queue *)obj;
447 return is_signaled( queue );
450 static int msg_queue_satisfied( struct object *obj, struct thread *thread )
452 struct msg_queue *queue = (struct msg_queue *)obj;
453 queue->wake_mask = 0;
454 queue->changed_mask = 0;
455 return 0; /* Not abandoned */
458 static void msg_queue_destroy( struct object *obj )
460 struct msg_queue *queue = (struct msg_queue *)obj;
461 struct timer *timer = queue->first_timer;
462 int i;
464 cleanup_results( queue );
465 for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
467 while (timer)
469 struct timer *next = timer->next;
470 free( timer );
471 timer = next;
473 if (queue->timeout) remove_timeout_user( queue->timeout );
476 /* set the next timer to expire */
477 static void set_next_timer( struct msg_queue *queue, struct timer *timer )
479 if (queue->timeout)
481 remove_timeout_user( queue->timeout );
482 queue->timeout = NULL;
484 if ((queue->next_timer = timer))
485 queue->timeout = add_timeout_user( &timer->when, timer_callback, queue );
487 /* set/clear QS_TIMER bit */
488 if (queue->next_timer == queue->first_timer)
489 clear_queue_bits( queue, QS_TIMER );
490 else
491 set_queue_bits( queue, QS_TIMER );
494 /* callback for the next timer expiration */
495 static void timer_callback( void *private )
497 struct msg_queue *queue = private;
499 queue->timeout = NULL;
500 /* move on to the next timer */
501 set_next_timer( queue, queue->next_timer->next );
504 /* link a timer at its rightful place in the queue list */
505 static void link_timer( struct msg_queue *queue, struct timer *timer )
507 struct timer *pos = queue->next_timer;
509 while (pos && time_before( &pos->when, &timer->when )) pos = pos->next;
511 if (pos) /* insert before pos */
513 if ((timer->prev = pos->prev)) timer->prev->next = timer;
514 else queue->first_timer = timer;
515 timer->next = pos;
516 pos->prev = timer;
518 else /* insert at end */
520 timer->next = NULL;
521 timer->prev = queue->last_timer;
522 if (queue->last_timer) queue->last_timer->next = timer;
523 else queue->first_timer = timer;
524 queue->last_timer = timer;
526 /* check if we replaced the next timer */
527 if (pos == queue->next_timer) set_next_timer( queue, timer );
530 /* remove a timer from the queue timer list */
531 static void unlink_timer( struct msg_queue *queue, struct timer *timer )
533 if (timer->next) timer->next->prev = timer->prev;
534 else queue->last_timer = timer->prev;
535 if (timer->prev) timer->prev->next = timer->next;
536 else queue->first_timer = timer->next;
537 /* check if we removed the next timer */
538 if (queue->next_timer == timer) set_next_timer( queue, timer->next );
539 else if (queue->next_timer == queue->first_timer) clear_queue_bits( queue, QS_TIMER );
542 /* restart an expired timer */
543 static void restart_timer( struct msg_queue *queue, struct timer *timer )
545 struct timeval now;
546 unlink_timer( queue, timer );
547 gettimeofday( &now, 0 );
548 while (!time_before( &now, &timer->when )) add_timeout( &timer->when, timer->rate );
549 link_timer( queue, timer );
552 /* find an expired timer matching the filtering parameters */
553 static struct timer *find_expired_timer( struct msg_queue *queue, handle_t win,
554 unsigned int get_first, unsigned int get_last,
555 int remove )
557 struct timer *timer;
558 for (timer = queue->first_timer; (timer && timer != queue->next_timer); timer = timer->next)
560 if (win && timer->win != win) continue;
561 if (timer->msg >= get_first && timer->msg <= get_last)
563 if (remove) restart_timer( queue, timer );
564 return timer;
567 return NULL;
570 /* kill a timer */
571 static int kill_timer( struct msg_queue *queue, handle_t win, unsigned int msg, unsigned int id )
573 struct timer *timer;
575 for (timer = queue->first_timer; timer; timer = timer->next)
577 if (timer->win != win || timer->msg != msg || timer->id != id) continue;
578 unlink_timer( queue, timer );
579 free( timer );
580 return 1;
582 return 0;
585 /* add a timer */
586 static struct timer *set_timer( struct msg_queue *queue, unsigned int rate )
588 struct timer *timer = mem_alloc( sizeof(*timer) );
589 if (timer)
591 timer->rate = rate;
592 gettimeofday( &timer->when, 0 );
593 add_timeout( &timer->when, rate );
594 link_timer( queue, timer );
596 return timer;
599 /* remove all messages and timers belonging to a certain window */
600 static void cleanup_window( struct msg_queue *queue, handle_t win )
602 struct timer *timer;
603 struct message *msg;
604 int i;
606 /* remove timers */
607 timer = queue->first_timer;
608 while (timer)
610 struct timer *next = timer->next;
611 if (timer->win == win)
613 unlink_timer( queue, timer );
614 free( timer );
616 timer = next;
619 /* remove messages */
620 for (i = 0; i < NB_MSG_KINDS; i++)
622 msg = queue->msg_list[i].first;
623 while (msg)
625 struct message *next = msg->next;
626 if (msg->win == win) remove_queue_message( queue, msg, i );
627 msg = next;
632 /* get the message queue of the current thread */
633 DECL_HANDLER(get_msg_queue)
635 struct msg_queue *queue = get_current_queue();
637 req->handle = 0;
638 if (queue) req->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
642 /* increment the message queue paint count */
643 DECL_HANDLER(inc_queue_paint_count)
645 struct msg_queue *queue;
646 struct thread *thread = get_thread_from_id( req->id );
648 if (!thread) return;
650 if ((queue = thread->queue))
652 if ((queue->paint_count += req->incr) < 0) queue->paint_count = 0;
654 if (queue->paint_count)
655 set_queue_bits( queue, QS_PAINT );
656 else
657 clear_queue_bits( queue, QS_PAINT );
659 else set_error( STATUS_INVALID_PARAMETER );
661 release_object( thread );
666 /* set the current message queue wakeup mask */
667 DECL_HANDLER(set_queue_mask)
669 struct msg_queue *queue = get_current_queue();
671 if (queue)
673 queue->wake_mask = req->wake_mask;
674 queue->changed_mask = req->changed_mask;
675 req->wake_bits = queue->wake_bits;
676 req->changed_bits = queue->changed_bits;
677 if (is_signaled( queue ))
679 /* if skip wait is set, do what would have been done in the subsequent wait */
680 if (req->skip_wait) msg_queue_satisfied( &queue->obj, current );
681 else wake_up( &queue->obj, 0 );
687 /* get the current message queue status */
688 DECL_HANDLER(get_queue_status)
690 struct msg_queue *queue = current->queue;
691 if (queue)
693 req->wake_bits = queue->wake_bits;
694 req->changed_bits = queue->changed_bits;
695 if (req->clear) queue->changed_bits = 0;
697 else req->wake_bits = req->changed_bits = 0;
701 /* send a message to a thread queue */
702 DECL_HANDLER(send_message)
704 struct message *msg;
705 struct msg_queue *send_queue = get_current_queue();
706 struct msg_queue *recv_queue;
707 struct thread *thread = get_thread_from_id( req->id );
709 if (!thread) return;
711 if (!(recv_queue = thread->queue))
713 set_error( STATUS_INVALID_PARAMETER );
714 release_object( thread );
715 return;
718 if ((msg = mem_alloc( sizeof(*msg) )))
720 msg->type = req->type;
721 msg->win = req->win;
722 msg->msg = req->msg;
723 msg->wparam = req->wparam;
724 msg->lparam = req->lparam;
725 msg->time = req->time;
726 msg->x = req->x;
727 msg->y = req->y;
728 msg->info = req->info;
729 msg->result = NULL;
730 msg->data = NULL;
731 msg->data_size = 0;
733 switch(msg->type)
735 case MSG_OTHER_PROCESS:
736 msg->data_size = get_req_data_size(req);
737 if (msg->data_size && !(msg->data = memdup( get_req_data(req), msg->data_size )))
739 free( msg );
740 break;
742 /* fall through */
743 case MSG_ASCII:
744 case MSG_UNICODE:
745 case MSG_CALLBACK:
746 if (!(msg->result = alloc_message_result( send_queue, recv_queue, req->timeout )))
748 free( msg );
749 break;
751 /* fall through */
752 case MSG_NOTIFY:
753 append_message( &recv_queue->msg_list[SEND_MESSAGE], msg );
754 set_queue_bits( recv_queue, QS_SENDMESSAGE );
755 break;
756 case MSG_POSTED:
757 append_message( &recv_queue->msg_list[POST_MESSAGE], msg );
758 set_queue_bits( recv_queue, QS_POSTMESSAGE );
759 break;
760 case MSG_HARDWARE_RAW:
761 case MSG_HARDWARE_COOKED:
763 struct message_list *list = ((msg->type == MSG_HARDWARE_RAW) ?
764 &recv_queue->msg_list[RAW_HW_MESSAGE] :
765 &recv_queue->msg_list[COOKED_HW_MESSAGE]);
766 if (msg->msg == WM_MOUSEMOVE && merge_message( list, msg ))
768 free( msg );
769 break;
771 append_message( list, msg );
772 set_queue_bits( recv_queue, get_hardware_msg_bit(msg) );
773 break;
775 default:
776 set_error( STATUS_INVALID_PARAMETER );
777 free( msg );
778 break;
781 release_object( thread );
784 /* store a message contents into the request buffer; helper for get_message */
785 inline static void put_req_message( struct get_message_request *req, const struct message *msg )
787 int len = min( get_req_data_size(req), msg->data_size );
789 req->type = msg->type;
790 req->win = msg->win;
791 req->msg = msg->msg;
792 req->wparam = msg->wparam;
793 req->lparam = msg->lparam;
794 req->x = msg->x;
795 req->y = msg->y;
796 req->time = msg->time;
797 req->info = msg->info;
798 if (len) memcpy( get_req_data(req), msg->data, len );
799 set_req_data_size( req, len );
802 /* return a message to the application, removing it from the queue if needed */
803 static void return_message_to_app( struct msg_queue *queue, struct get_message_request *req,
804 struct message *msg, enum message_kind kind )
806 put_req_message( req, msg );
807 /* raw messages always get removed */
808 if ((msg->type == MSG_HARDWARE_RAW) || (req->flags & GET_MSG_REMOVE))
810 queue->last_msg = NULL;
811 remove_queue_message( queue, msg, kind );
813 else /* remember it as the last returned message */
815 queue->last_msg = msg;
816 queue->last_msg_kind = kind;
821 inline static struct message *find_matching_message( const struct message_list *list, handle_t win,
822 unsigned int first, unsigned int last )
824 struct message *msg;
826 for (msg = list->first; msg; msg = msg->next)
828 /* check against the filters */
829 if (msg->msg == WM_QUIT) break; /* WM_QUIT is never filtered */
830 if (win && msg->win && msg->win != win) continue;
831 if (msg->msg < first) continue;
832 if (msg->msg > last) continue;
833 break; /* found one */
835 return msg;
839 /* get a message from the current queue */
840 DECL_HANDLER(get_message)
842 struct timer *timer;
843 struct message *msg;
844 struct msg_queue *queue = get_current_queue();
846 if (!queue)
848 set_req_data_size( req, 0 );
849 return;
852 /* first check for sent messages */
853 if ((msg = queue->msg_list[SEND_MESSAGE].first))
855 put_req_message( req, msg );
856 receive_message( queue, msg );
857 return;
859 set_req_data_size( req, 0 ); /* only sent messages can have data */
860 if (req->flags & GET_MSG_SENT_ONLY) goto done; /* nothing else to check */
862 /* if requested, remove the last returned but not yet removed message */
863 if ((req->flags & GET_MSG_REMOVE_LAST) && queue->last_msg)
864 remove_queue_message( queue, queue->last_msg, queue->last_msg_kind );
865 queue->last_msg = NULL;
867 /* clear changed bits so we can wait on them if we don't find a message */
868 queue->changed_bits = 0;
870 /* then check for posted messages */
871 if ((msg = find_matching_message( &queue->msg_list[POST_MESSAGE], req->get_win,
872 req->get_first, req->get_last )))
874 return_message_to_app( queue, req, msg, POST_MESSAGE );
875 return;
878 /* then check for cooked hardware messages */
879 if ((msg = find_matching_message( &queue->msg_list[COOKED_HW_MESSAGE], req->get_win,
880 req->get_first, req->get_last )))
882 return_message_to_app( queue, req, msg, COOKED_HW_MESSAGE );
883 return;
886 /* then check for any raw hardware message */
887 if ((msg = queue->msg_list[RAW_HW_MESSAGE].first))
889 return_message_to_app( queue, req, msg, RAW_HW_MESSAGE );
890 return;
893 /* now check for WM_PAINT */
894 if ((queue->wake_bits & QS_PAINT) &&
895 (WM_PAINT >= req->get_first) && (WM_PAINT <= req->get_last))
897 req->type = MSG_POSTED;
898 req->win = 0;
899 req->msg = WM_PAINT;
900 req->wparam = 0;
901 req->lparam = 0;
902 req->x = 0;
903 req->y = 0;
904 req->time = 0;
905 req->info = 0;
906 return;
909 /* now check for timer */
910 if ((timer = find_expired_timer( queue, req->get_win, req->get_first,
911 req->get_last, (req->flags & GET_MSG_REMOVE) )))
913 req->type = MSG_POSTED;
914 req->win = timer->win;
915 req->msg = timer->msg;
916 req->wparam = timer->id;
917 req->lparam = timer->lparam;
918 req->x = 0;
919 req->y = 0;
920 req->time = 0;
921 req->info = 0;
922 return;
925 done:
926 set_error( STATUS_PENDING ); /* FIXME */
930 /* reply to a sent message */
931 DECL_HANDLER(reply_message)
933 if (current->queue && current->queue->recv_result)
934 reply_message( current->queue, req->result, 0, req->remove,
935 get_req_data(req), get_req_data_size(req) );
936 else
937 set_error( STATUS_ACCESS_DENIED );
941 /* retrieve the reply for the last message sent */
942 DECL_HANDLER(get_message_reply)
944 struct msg_queue *queue = current->queue;
945 size_t data_len = 0;
947 if (queue)
949 struct message_result *result = queue->send_result;
951 set_error( STATUS_PENDING );
952 req->result = 0;
954 if (result && (result->replied || req->cancel))
956 if (result->replied)
958 req->result = result->result;
959 set_error( result->error );
960 if (result->data)
962 data_len = min( result->data_size, get_req_data_size(req) );
963 memcpy( get_req_data(req), result->data, data_len );
964 free( result->data );
965 result->data = NULL;
966 result->data_size = 0;
969 queue->send_result = result->send_next;
970 result->sender = NULL;
971 if (!result->receiver) free_result( result );
972 if (!queue->send_result || !queue->send_result->replied)
973 clear_queue_bits( queue, QS_SMRESULT );
976 else set_error( STATUS_ACCESS_DENIED );
977 set_req_data_size( req, data_len );
981 /* cleanup a queue when a window is deleted */
982 DECL_HANDLER(cleanup_window_queue)
984 if (current->queue) cleanup_window( current->queue, req->win );
988 /* set a window timer */
989 DECL_HANDLER(set_win_timer)
991 struct timer *timer;
992 struct msg_queue *queue = get_current_queue();
994 if (!queue) return;
996 /* remove it if it existed already */
997 if (req->win) kill_timer( queue, req->win, req->msg, req->id );
999 if ((timer = set_timer( queue, req->rate )))
1001 timer->win = req->win;
1002 timer->msg = req->msg;
1003 timer->id = req->id;
1004 timer->lparam = req->lparam;
1008 /* kill a window timer */
1009 DECL_HANDLER(kill_win_timer)
1011 struct msg_queue *queue = current->queue;
1013 if (!queue || !kill_timer( queue, req->win, req->msg, req->id ))
1014 set_error( STATUS_INVALID_PARAMETER );