Moved mode setting out of .spec file into Makefile.
[wine/multimedia.git] / server / queue.c
blobe250faecb4e473ffea0b7576668f329cf2539d4f
1 /*
2 * Server-side message queues
4 * Copyright (C) 2000 Alexandre Julliard
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <stdio.h>
26 #include <stdlib.h>
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
32 #include "handle.h"
33 #include "thread.h"
34 #include "process.h"
35 #include "request.h"
36 #include "user.h"
38 enum message_kind { SEND_MESSAGE, POST_MESSAGE, COOKED_HW_MESSAGE, RAW_HW_MESSAGE };
39 #define NB_MSG_KINDS (RAW_HW_MESSAGE+1)
42 struct message_result
44 struct message_result *send_next; /* next in sender list */
45 struct message_result *recv_next; /* next in receiver list */
46 struct msg_queue *sender; /* sender queue */
47 struct msg_queue *receiver; /* receiver queue */
48 int replied; /* has it been replied to? */
49 unsigned int result; /* reply result */
50 unsigned int error; /* error code to pass back to sender */
51 void *data; /* message reply data */
52 unsigned int data_size; /* size of message reply data */
53 struct timeout_user *timeout; /* result timeout */
56 struct message
58 struct message *next; /* next message in list */
59 struct message *prev; /* prev message in list */
60 enum message_type type; /* message type */
61 user_handle_t win; /* window handle */
62 unsigned int msg; /* message code */
63 unsigned int wparam; /* parameters */
64 unsigned int lparam; /* parameters */
65 int x; /* x position */
66 int y; /* y position */
67 unsigned int time; /* message time */
68 unsigned int info; /* extra info */
69 void *data; /* message data for sent messages */
70 unsigned int data_size; /* size of message data */
71 struct message_result *result; /* result in sender queue */
74 struct message_list
76 struct message *first; /* head of list */
77 struct message *last; /* tail of list */
80 struct timer
82 struct timer *next; /* next timer in list */
83 struct timer *prev; /* prev timer in list */
84 struct timeval when; /* next expiration */
85 unsigned int rate; /* timer rate in ms */
86 user_handle_t win; /* window handle */
87 unsigned int msg; /* message to post */
88 unsigned int id; /* timer id */
89 unsigned int lparam; /* lparam for message */
92 struct msg_queue
94 struct object obj; /* object header */
95 unsigned int wake_bits; /* wakeup bits */
96 unsigned int wake_mask; /* wakeup mask */
97 unsigned int changed_bits; /* changed wakeup bits */
98 unsigned int changed_mask; /* changed wakeup mask */
99 int paint_count; /* pending paint messages count */
100 struct message_list msg_list[NB_MSG_KINDS]; /* lists of messages */
101 struct message_result *send_result; /* stack of sent messages waiting for result */
102 struct message_result *recv_result; /* stack of received messages waiting for result */
103 struct message *last_msg; /* last msg returned to the app and not removed */
104 enum message_kind last_msg_kind; /* message kind of last_msg */
105 struct timer *first_timer; /* head of timer list */
106 struct timer *last_timer; /* tail of timer list */
107 struct timer *next_timer; /* next timer to expire */
108 struct timeout_user *timeout; /* timeout for next timer to expire */
111 static void msg_queue_dump( struct object *obj, int verbose );
112 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry );
113 static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
114 static int msg_queue_signaled( struct object *obj, struct thread *thread );
115 static int msg_queue_satisfied( struct object *obj, struct thread *thread );
116 static void msg_queue_destroy( struct object *obj );
117 static void timer_callback( void *private );
119 static const struct object_ops msg_queue_ops =
121 sizeof(struct msg_queue), /* size */
122 msg_queue_dump, /* dump */
123 msg_queue_add_queue, /* add_queue */
124 msg_queue_remove_queue, /* remove_queue */
125 msg_queue_signaled, /* signaled */
126 msg_queue_satisfied, /* satisfied */
127 NULL, /* get_poll_events */
128 NULL, /* poll_event */
129 no_get_fd, /* get_fd */
130 no_flush, /* flush */
131 no_get_file_info, /* get_file_info */
132 NULL, /* queue_async */
133 msg_queue_destroy /* destroy */
137 static struct msg_queue *create_msg_queue( struct thread *thread )
139 struct msg_queue *queue;
140 int i;
142 if ((queue = alloc_object( &msg_queue_ops, -1 )))
144 queue->wake_bits = 0;
145 queue->wake_mask = 0;
146 queue->changed_bits = 0;
147 queue->changed_mask = 0;
148 queue->paint_count = 0;
149 queue->send_result = NULL;
150 queue->recv_result = NULL;
151 queue->last_msg = NULL;
152 queue->first_timer = NULL;
153 queue->last_timer = NULL;
154 queue->next_timer = NULL;
155 queue->timeout = NULL;
156 for (i = 0; i < NB_MSG_KINDS; i++)
157 queue->msg_list[i].first = queue->msg_list[i].last = NULL;
159 thread->queue = queue;
160 if (!thread->process->queue)
161 thread->process->queue = (struct msg_queue *)grab_object( queue );
163 return queue;
166 /* free the message queue of a thread at thread exit */
167 void free_msg_queue( struct thread *thread )
169 struct process *process = thread->process;
171 if (!thread->queue) return;
172 if (process->queue == thread->queue) /* is it the process main queue? */
174 release_object( process->queue );
175 process->queue = NULL;
176 if (process->idle_event)
178 set_event( process->idle_event );
179 release_object( process->idle_event );
180 process->idle_event = NULL;
183 release_object( thread->queue );
184 thread->queue = NULL;
187 /* check the queue status */
188 inline static int is_signaled( struct msg_queue *queue )
190 return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
193 /* set some queue bits */
194 inline static void set_queue_bits( struct msg_queue *queue, unsigned int bits )
196 queue->wake_bits |= bits;
197 queue->changed_bits |= bits;
198 if (is_signaled( queue )) wake_up( &queue->obj, 0 );
201 /* clear some queue bits */
202 inline static void clear_queue_bits( struct msg_queue *queue, unsigned int bits )
204 queue->wake_bits &= ~bits;
205 queue->changed_bits &= ~bits;
208 /* get the QS_* bit corresponding to a given hardware message */
209 inline static int get_hardware_msg_bit( struct message *msg )
211 if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
212 if (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST) return QS_KEY;
213 return QS_MOUSEBUTTON;
216 /* get the current thread queue, creating it if needed */
217 inline static struct msg_queue *get_current_queue(void)
219 struct msg_queue *queue = current->queue;
220 if (!queue) queue = create_msg_queue( current );
221 return queue;
224 /* append a message to the end of a list */
225 inline static void append_message( struct message_list *list, struct message *msg )
227 msg->next = NULL;
228 if ((msg->prev = list->last)) msg->prev->next = msg;
229 else list->first = msg;
230 list->last = msg;
233 /* unlink a message from a list it */
234 inline static void unlink_message( struct message_list *list, struct message *msg )
236 if (msg->next) msg->next->prev = msg->prev;
237 else list->last = msg->prev;
238 if (msg->prev) msg->prev->next = msg->next;
239 else list->first = msg->next;
242 /* try to merge a message with the last in the list; return 1 if successful */
243 static int merge_message( struct message_list *list, const struct message *msg )
245 struct message *prev = list->last;
247 if (!prev) return 0;
248 if (prev->result) return 0;
249 if (prev->win != msg->win) return 0;
250 if (prev->msg != msg->msg) return 0;
251 if (prev->type != msg->type) return 0;
252 /* now we can merge it */
253 prev->wparam = msg->wparam;
254 prev->lparam = msg->lparam;
255 prev->x = msg->x;
256 prev->y = msg->y;
257 prev->time = msg->time;
258 prev->info = msg->info;
259 return 1;
262 /* free a result structure */
263 static void free_result( struct message_result *result )
265 if (result->timeout) remove_timeout_user( result->timeout );
266 if (result->data) free( result->data );
267 free( result );
270 /* store the message result in the appropriate structure */
271 static void store_message_result( struct message_result *res, unsigned int result,
272 unsigned int error )
274 res->result = result;
275 res->error = error;
276 res->replied = 1;
277 if (res->timeout)
279 remove_timeout_user( res->timeout );
280 res->timeout = NULL;
282 /* wake sender queue if waiting on this result */
283 if (res->sender && res->sender->send_result == res)
284 set_queue_bits( res->sender, QS_SMRESULT );
287 /* free a message when deleting a queue or window */
288 static void free_message( struct message *msg )
290 struct message_result *result = msg->result;
291 if (result)
293 if (result->sender)
295 result->receiver = NULL;
296 store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ );
298 else free_result( result );
300 if (msg->data) free( msg->data );
301 free( msg );
304 /* remove (and free) a message from a message list */
305 static void remove_queue_message( struct msg_queue *queue, struct message *msg,
306 enum message_kind kind )
308 int clr_bit;
309 struct message *other;
311 if (queue->last_msg == msg) queue->last_msg = NULL;
312 unlink_message( &queue->msg_list[kind], msg );
313 switch(kind)
315 case SEND_MESSAGE:
316 if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_SENDMESSAGE );
317 break;
318 case POST_MESSAGE:
319 if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_POSTMESSAGE );
320 break;
321 case COOKED_HW_MESSAGE:
322 case RAW_HW_MESSAGE:
323 clr_bit = get_hardware_msg_bit( msg );
324 for (other = queue->msg_list[kind].first; other; other = other->next)
325 if (get_hardware_msg_bit( other ) == clr_bit) break;
326 if (!other) clear_queue_bits( queue, clr_bit );
327 break;
329 free_message( msg );
332 /* message timed out without getting a reply */
333 static void result_timeout( void *private )
335 struct message_result *result = private;
337 assert( !result->replied );
339 result->timeout = NULL;
340 store_message_result( result, 0, STATUS_TIMEOUT );
343 /* allocate and fill a message result structure */
344 static struct message_result *alloc_message_result( struct msg_queue *send_queue,
345 struct msg_queue *recv_queue,
346 unsigned int timeout )
348 struct message_result *result = mem_alloc( sizeof(*result) );
349 if (result)
351 /* put the result on the sender result stack */
352 result->sender = send_queue;
353 result->receiver = recv_queue;
354 result->replied = 0;
355 result->data = NULL;
356 result->data_size = 0;
357 result->timeout = NULL;
358 result->send_next = send_queue->send_result;
359 send_queue->send_result = result;
360 if (timeout != -1)
362 struct timeval when;
363 gettimeofday( &when, 0 );
364 add_timeout( &when, timeout );
365 result->timeout = add_timeout_user( &when, result_timeout, result );
368 return result;
371 /* receive a message, removing it from the sent queue */
372 static void receive_message( struct msg_queue *queue, struct message *msg,
373 struct get_message_reply *reply )
375 struct message_result *result = msg->result;
377 reply->total = msg->data_size;
378 if (msg->data_size > get_reply_max_size())
380 set_error( STATUS_BUFFER_OVERFLOW );
381 return;
383 reply->type = msg->type;
384 reply->win = msg->win;
385 reply->msg = msg->msg;
386 reply->wparam = msg->wparam;
387 reply->lparam = msg->lparam;
388 reply->x = msg->x;
389 reply->y = msg->y;
390 reply->time = msg->time;
391 reply->info = msg->info;
393 if (msg->data) set_reply_data_ptr( msg->data, msg->data_size );
395 unlink_message( &queue->msg_list[SEND_MESSAGE], msg );
396 /* put the result on the receiver result stack */
397 if (result)
399 result->recv_next = queue->recv_result;
400 queue->recv_result = result;
402 free( msg );
403 if (!queue->msg_list[SEND_MESSAGE].first) clear_queue_bits( queue, QS_SENDMESSAGE );
406 /* set the result of the current received message */
407 static void reply_message( struct msg_queue *queue, unsigned int result,
408 unsigned int error, int remove, const void *data, size_t len )
410 struct message_result *res = queue->recv_result;
412 if (remove)
414 queue->recv_result = res->recv_next;
415 res->receiver = NULL;
416 if (!res->sender) /* no one waiting for it */
418 free_result( res );
419 return;
422 if (!res->replied)
424 if (len && (res->data = memdup( data, len ))) res->data_size = len;
425 store_message_result( res, result, error );
429 /* empty a message list and free all the messages */
430 static void empty_msg_list( struct message_list *list )
432 struct message *msg = list->first;
433 while (msg)
435 struct message *next = msg->next;
436 free_message( msg );
437 msg = next;
441 /* cleanup all pending results when deleting a queue */
442 static void cleanup_results( struct msg_queue *queue )
444 struct message_result *result, *next;
446 result = queue->send_result;
447 while (result)
449 next = result->send_next;
450 result->sender = NULL;
451 if (!result->receiver) free_result( result );
452 result = next;
455 while (queue->recv_result)
456 reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
459 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
461 struct msg_queue *queue = (struct msg_queue *)obj;
462 struct process *process = entry->thread->process;
464 /* a thread can only wait on its own queue */
465 if (entry->thread->queue != queue)
467 set_error( STATUS_ACCESS_DENIED );
468 return 0;
470 /* if waiting on the main process queue, set the idle event */
471 if (process->queue == queue)
473 if (process->idle_event) set_event( process->idle_event );
475 add_queue( obj, entry );
476 return 1;
479 static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *entry )
481 struct msg_queue *queue = (struct msg_queue *)obj;
482 struct process *process = entry->thread->process;
484 remove_queue( obj, entry );
486 assert( entry->thread->queue == queue );
488 /* if waiting on the main process queue, reset the idle event */
489 if (process->queue == queue)
491 if (process->idle_event) reset_event( process->idle_event );
495 static void msg_queue_dump( struct object *obj, int verbose )
497 struct msg_queue *queue = (struct msg_queue *)obj;
498 fprintf( stderr, "Msg queue bits=%x mask=%x\n",
499 queue->wake_bits, queue->wake_mask );
502 static int msg_queue_signaled( struct object *obj, struct thread *thread )
504 struct msg_queue *queue = (struct msg_queue *)obj;
505 return is_signaled( queue );
508 static int msg_queue_satisfied( struct object *obj, struct thread *thread )
510 struct msg_queue *queue = (struct msg_queue *)obj;
511 queue->wake_mask = 0;
512 queue->changed_mask = 0;
513 return 0; /* Not abandoned */
516 static void msg_queue_destroy( struct object *obj )
518 struct msg_queue *queue = (struct msg_queue *)obj;
519 struct timer *timer = queue->first_timer;
520 int i;
522 cleanup_results( queue );
523 for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
525 while (timer)
527 struct timer *next = timer->next;
528 free( timer );
529 timer = next;
531 if (queue->timeout) remove_timeout_user( queue->timeout );
534 /* set the next timer to expire */
535 static void set_next_timer( struct msg_queue *queue, struct timer *timer )
537 if (queue->timeout)
539 remove_timeout_user( queue->timeout );
540 queue->timeout = NULL;
542 if ((queue->next_timer = timer))
543 queue->timeout = add_timeout_user( &timer->when, timer_callback, queue );
545 /* set/clear QS_TIMER bit */
546 if (queue->next_timer == queue->first_timer)
547 clear_queue_bits( queue, QS_TIMER );
548 else
549 set_queue_bits( queue, QS_TIMER );
552 /* callback for the next timer expiration */
553 static void timer_callback( void *private )
555 struct msg_queue *queue = private;
557 queue->timeout = NULL;
558 /* move on to the next timer */
559 set_next_timer( queue, queue->next_timer->next );
562 /* link a timer at its rightful place in the queue list */
563 static void link_timer( struct msg_queue *queue, struct timer *timer )
565 struct timer *pos = queue->next_timer;
567 while (pos && time_before( &pos->when, &timer->when )) pos = pos->next;
569 if (pos) /* insert before pos */
571 if ((timer->prev = pos->prev)) timer->prev->next = timer;
572 else queue->first_timer = timer;
573 timer->next = pos;
574 pos->prev = timer;
576 else /* insert at end */
578 timer->next = NULL;
579 timer->prev = queue->last_timer;
580 if (queue->last_timer) queue->last_timer->next = timer;
581 else queue->first_timer = timer;
582 queue->last_timer = timer;
584 /* check if we replaced the next timer */
585 if (pos == queue->next_timer) set_next_timer( queue, timer );
588 /* remove a timer from the queue timer list */
589 static void unlink_timer( struct msg_queue *queue, struct timer *timer )
591 if (timer->next) timer->next->prev = timer->prev;
592 else queue->last_timer = timer->prev;
593 if (timer->prev) timer->prev->next = timer->next;
594 else queue->first_timer = timer->next;
595 /* check if we removed the next timer */
596 if (queue->next_timer == timer) set_next_timer( queue, timer->next );
597 else if (queue->next_timer == queue->first_timer) clear_queue_bits( queue, QS_TIMER );
600 /* restart an expired timer */
601 static void restart_timer( struct msg_queue *queue, struct timer *timer )
603 struct timeval now;
604 unlink_timer( queue, timer );
605 gettimeofday( &now, 0 );
606 while (!time_before( &now, &timer->when )) add_timeout( &timer->when, timer->rate );
607 link_timer( queue, timer );
610 /* find an expired timer matching the filtering parameters */
611 static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t win,
612 unsigned int get_first, unsigned int get_last,
613 int remove )
615 struct timer *timer;
616 for (timer = queue->first_timer; (timer && timer != queue->next_timer); timer = timer->next)
618 if (win && timer->win != win) continue;
619 if (timer->msg >= get_first && timer->msg <= get_last)
621 if (remove) restart_timer( queue, timer );
622 return timer;
625 return NULL;
628 /* kill a timer */
629 static int kill_timer( struct msg_queue *queue, user_handle_t win,
630 unsigned int msg, unsigned int id )
632 struct timer *timer;
634 for (timer = queue->first_timer; timer; timer = timer->next)
636 if (timer->win != win || timer->msg != msg || timer->id != id) continue;
637 unlink_timer( queue, timer );
638 free( timer );
639 return 1;
641 return 0;
644 /* add a timer */
645 static struct timer *set_timer( struct msg_queue *queue, unsigned int rate )
647 struct timer *timer = mem_alloc( sizeof(*timer) );
648 if (timer)
650 timer->rate = rate;
651 gettimeofday( &timer->when, 0 );
652 add_timeout( &timer->when, rate );
653 link_timer( queue, timer );
655 return timer;
659 /* increment (or decrement if 'incr' is negative) the queue paint count */
660 void inc_queue_paint_count( struct thread *thread, int incr )
662 struct msg_queue *queue = thread->queue;
664 assert( queue );
666 if ((queue->paint_count += incr) < 0) queue->paint_count = 0;
668 if (queue->paint_count)
669 set_queue_bits( queue, QS_PAINT );
670 else
671 clear_queue_bits( queue, QS_PAINT );
675 /* remove all messages and timers belonging to a certain window */
676 void queue_cleanup_window( struct thread *thread, user_handle_t win )
678 struct msg_queue *queue = thread->queue;
679 struct timer *timer;
680 struct message *msg;
681 int i;
683 if (!queue) return;
685 /* remove timers */
686 timer = queue->first_timer;
687 while (timer)
689 struct timer *next = timer->next;
690 if (timer->win == win)
692 unlink_timer( queue, timer );
693 free( timer );
695 timer = next;
698 /* remove messages */
699 for (i = 0; i < NB_MSG_KINDS; i++)
701 msg = queue->msg_list[i].first;
702 while (msg)
704 struct message *next = msg->next;
705 if (msg->win == win) remove_queue_message( queue, msg, i );
706 msg = next;
711 /* post a message to a window; used by socket handling */
712 void post_message( user_handle_t win, unsigned int message,
713 unsigned int wparam, unsigned int lparam )
715 struct message *msg;
716 struct thread *thread = get_window_thread( win );
718 if (!thread) return;
720 if (thread->queue && (msg = mem_alloc( sizeof(*msg) )))
722 msg->type = MSG_POSTED;
723 msg->win = get_user_full_handle( win );
724 msg->msg = message;
725 msg->wparam = wparam;
726 msg->lparam = lparam;
727 msg->time = get_tick_count();
728 msg->x = 0;
729 msg->y = 0;
730 msg->info = 0;
731 msg->result = NULL;
732 msg->data = NULL;
733 msg->data_size = 0;
735 append_message( &thread->queue->msg_list[POST_MESSAGE], msg );
736 set_queue_bits( thread->queue, QS_POSTMESSAGE );
738 release_object( thread );
742 /* get the message queue of the current thread */
743 DECL_HANDLER(get_msg_queue)
745 struct msg_queue *queue = get_current_queue();
747 reply->handle = 0;
748 if (queue) reply->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
752 /* set the current message queue wakeup mask */
753 DECL_HANDLER(set_queue_mask)
755 struct msg_queue *queue = get_current_queue();
757 if (queue)
759 queue->wake_mask = req->wake_mask;
760 queue->changed_mask = req->changed_mask;
761 reply->wake_bits = queue->wake_bits;
762 reply->changed_bits = queue->changed_bits;
763 if (is_signaled( queue ))
765 /* if skip wait is set, do what would have been done in the subsequent wait */
766 if (req->skip_wait) msg_queue_satisfied( &queue->obj, current );
767 else wake_up( &queue->obj, 0 );
773 /* get the current message queue status */
774 DECL_HANDLER(get_queue_status)
776 struct msg_queue *queue = current->queue;
777 if (queue)
779 reply->wake_bits = queue->wake_bits;
780 reply->changed_bits = queue->changed_bits;
781 if (req->clear) queue->changed_bits = 0;
783 else reply->wake_bits = reply->changed_bits = 0;
787 /* send a message to a thread queue */
788 DECL_HANDLER(send_message)
790 struct message *msg;
791 struct msg_queue *send_queue = get_current_queue();
792 struct msg_queue *recv_queue;
793 struct thread *thread = get_thread_from_id( req->id );
795 if (!thread) return;
797 if (!(recv_queue = thread->queue))
799 set_error( STATUS_INVALID_PARAMETER );
800 release_object( thread );
801 return;
804 if ((msg = mem_alloc( sizeof(*msg) )))
806 msg->type = req->type;
807 msg->win = get_user_full_handle( req->win );
808 msg->msg = req->msg;
809 msg->wparam = req->wparam;
810 msg->lparam = req->lparam;
811 msg->time = req->time;
812 msg->x = req->x;
813 msg->y = req->y;
814 msg->info = req->info;
815 msg->result = NULL;
816 msg->data = NULL;
817 msg->data_size = 0;
819 switch(msg->type)
821 case MSG_OTHER_PROCESS:
822 msg->data_size = get_req_data_size();
823 if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size )))
825 free( msg );
826 break;
828 /* fall through */
829 case MSG_ASCII:
830 case MSG_UNICODE:
831 case MSG_CALLBACK:
832 if (!(msg->result = alloc_message_result( send_queue, recv_queue, req->timeout )))
834 free( msg );
835 break;
837 /* fall through */
838 case MSG_NOTIFY:
839 append_message( &recv_queue->msg_list[SEND_MESSAGE], msg );
840 set_queue_bits( recv_queue, QS_SENDMESSAGE );
841 break;
842 case MSG_POSTED:
843 /* needed for posted DDE messages */
844 msg->data_size = get_req_data_size();
845 if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size )))
847 free( msg );
848 break;
850 append_message( &recv_queue->msg_list[POST_MESSAGE], msg );
851 set_queue_bits( recv_queue, QS_POSTMESSAGE );
852 break;
853 case MSG_HARDWARE_RAW:
854 case MSG_HARDWARE_COOKED:
856 struct message_list *list = ((msg->type == MSG_HARDWARE_RAW) ?
857 &recv_queue->msg_list[RAW_HW_MESSAGE] :
858 &recv_queue->msg_list[COOKED_HW_MESSAGE]);
859 if (msg->msg == WM_MOUSEMOVE && merge_message( list, msg ))
861 free( msg );
862 break;
864 append_message( list, msg );
865 set_queue_bits( recv_queue, get_hardware_msg_bit(msg) );
866 break;
868 default:
869 set_error( STATUS_INVALID_PARAMETER );
870 free( msg );
871 break;
874 release_object( thread );
877 /* return a message to the application, removing it from the queue if needed */
878 static void return_message_to_app( struct msg_queue *queue, int flags,
879 struct get_message_reply *reply,
880 struct message *msg, enum message_kind kind )
882 reply->total = msg->data_size;
883 if (msg->data_size > get_reply_max_size())
885 set_error( STATUS_BUFFER_OVERFLOW );
886 return;
888 reply->type = msg->type;
889 reply->win = msg->win;
890 reply->msg = msg->msg;
891 reply->wparam = msg->wparam;
892 reply->lparam = msg->lparam;
893 reply->x = msg->x;
894 reply->y = msg->y;
895 reply->time = msg->time;
896 reply->info = msg->info;
898 /* raw messages always get removed */
899 if ((msg->type == MSG_HARDWARE_RAW) || (flags & GET_MSG_REMOVE))
901 queue->last_msg = NULL;
902 if (msg->data)
904 set_reply_data_ptr( msg->data, msg->data_size );
905 msg->data = NULL;
906 msg->data_size = 0;
908 remove_queue_message( queue, msg, kind );
910 else /* remember it as the last returned message */
912 if (msg->data) set_reply_data( msg->data, msg->data_size );
913 queue->last_msg = msg;
914 queue->last_msg_kind = kind;
919 inline static struct message *find_matching_message( const struct message_list *list,
920 user_handle_t win,
921 unsigned int first, unsigned int last )
923 struct message *msg;
925 for (msg = list->first; msg; msg = msg->next)
927 /* check against the filters */
928 if (msg->msg == WM_QUIT) break; /* WM_QUIT is never filtered */
929 if (win && msg->win && msg->win != win && !is_child_window( win, msg->win )) continue;
930 if (msg->msg < first) continue;
931 if (msg->msg > last) continue;
932 break; /* found one */
934 return msg;
938 /* get a message from the current queue */
939 DECL_HANDLER(get_message)
941 struct timer *timer;
942 struct message *msg;
943 struct msg_queue *queue = get_current_queue();
944 user_handle_t get_win = get_user_full_handle( req->get_win );
946 if (!queue) return;
948 /* first check for sent messages */
949 if ((msg = queue->msg_list[SEND_MESSAGE].first))
951 receive_message( queue, msg, reply );
952 return;
954 if (req->flags & GET_MSG_SENT_ONLY) goto done; /* nothing else to check */
956 /* if requested, remove the last returned but not yet removed message */
957 if ((req->flags & GET_MSG_REMOVE_LAST) && queue->last_msg)
958 remove_queue_message( queue, queue->last_msg, queue->last_msg_kind );
959 queue->last_msg = NULL;
961 /* clear changed bits so we can wait on them if we don't find a message */
962 queue->changed_bits = 0;
964 /* then check for posted messages */
965 if ((msg = find_matching_message( &queue->msg_list[POST_MESSAGE], get_win,
966 req->get_first, req->get_last )))
968 return_message_to_app( queue, req->flags, reply, msg, POST_MESSAGE );
969 return;
972 /* then check for cooked hardware messages */
973 if ((msg = find_matching_message( &queue->msg_list[COOKED_HW_MESSAGE], get_win,
974 req->get_first, req->get_last )))
976 return_message_to_app( queue, req->flags, reply, msg, COOKED_HW_MESSAGE );
977 return;
980 /* then check for any raw hardware message */
981 if ((msg = queue->msg_list[RAW_HW_MESSAGE].first))
983 return_message_to_app( queue, req->flags, reply, msg, RAW_HW_MESSAGE );
984 return;
987 /* now check for WM_PAINT */
988 if (queue->paint_count &&
989 (WM_PAINT >= req->get_first) && (WM_PAINT <= req->get_last) &&
990 (reply->win = find_window_to_repaint( get_win, current )))
992 reply->type = MSG_POSTED;
993 reply->msg = WM_PAINT;
994 reply->wparam = 0;
995 reply->lparam = 0;
996 reply->x = 0;
997 reply->y = 0;
998 reply->time = get_tick_count();
999 reply->info = 0;
1000 return;
1003 /* now check for timer */
1004 if ((timer = find_expired_timer( queue, get_win, req->get_first,
1005 req->get_last, (req->flags & GET_MSG_REMOVE) )))
1007 reply->type = MSG_POSTED;
1008 reply->win = timer->win;
1009 reply->msg = timer->msg;
1010 reply->wparam = timer->id;
1011 reply->lparam = timer->lparam;
1012 reply->x = 0;
1013 reply->y = 0;
1014 reply->time = get_tick_count();
1015 reply->info = 0;
1016 return;
1019 done:
1020 set_error( STATUS_PENDING ); /* FIXME */
1024 /* reply to a sent message */
1025 DECL_HANDLER(reply_message)
1027 if (current->queue && current->queue->recv_result)
1028 reply_message( current->queue, req->result, 0, req->remove,
1029 get_req_data(), get_req_data_size() );
1030 else
1031 set_error( STATUS_ACCESS_DENIED );
1035 /* retrieve the reply for the last message sent */
1036 DECL_HANDLER(get_message_reply)
1038 struct msg_queue *queue = current->queue;
1040 if (queue)
1042 struct message_result *result = queue->send_result;
1044 set_error( STATUS_PENDING );
1045 reply->result = 0;
1047 if (result && (result->replied || req->cancel))
1049 if (result->replied)
1051 reply->result = result->result;
1052 set_error( result->error );
1053 if (result->data)
1055 size_t data_len = min( result->data_size, get_reply_max_size() );
1056 set_reply_data_ptr( result->data, data_len );
1057 result->data = NULL;
1058 result->data_size = 0;
1061 queue->send_result = result->send_next;
1062 result->sender = NULL;
1063 if (!result->receiver) free_result( result );
1064 if (!queue->send_result || !queue->send_result->replied)
1065 clear_queue_bits( queue, QS_SMRESULT );
1068 else set_error( STATUS_ACCESS_DENIED );
1072 /* set a window timer */
1073 DECL_HANDLER(set_win_timer)
1075 struct timer *timer;
1076 struct msg_queue *queue = get_current_queue();
1077 user_handle_t win = get_user_full_handle( req->win );
1079 if (!queue) return;
1081 /* remove it if it existed already */
1082 if (win) kill_timer( queue, win, req->msg, req->id );
1084 if ((timer = set_timer( queue, req->rate )))
1086 timer->win = win;
1087 timer->msg = req->msg;
1088 timer->id = req->id;
1089 timer->lparam = req->lparam;
1093 /* kill a window timer */
1094 DECL_HANDLER(kill_win_timer)
1096 struct msg_queue *queue = current->queue;
1098 if (!queue || !kill_timer( queue, get_user_full_handle(req->win), req->msg, req->id ))
1099 set_error( STATUS_INVALID_PARAMETER );