Fixed some issues found by winapi_check.
[wine] / server / queue.c
1 /*
2  * Server-side message queues
3  *
4  * Copyright (C) 2000 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10
11 #include "winbase.h"
12 #include "wingdi.h"
13 #include "winuser.h"
14
15 #include "handle.h"
16 #include "thread.h"
17 #include "process.h"
18 #include "request.h"
19
20 struct message_result
21 {
22     struct message_result *send_next;   /* next in sender list */
23     struct message_result *recv_next;   /* next in receiver list */
24     struct msg_queue      *sender;      /* sender queue */
25     struct msg_queue      *receiver;    /* receiver queue */
26     int                    replied;     /* has it been replied to? */
27     unsigned int           result;      /* reply result */
28     unsigned int           error;       /* error code to pass back to sender */
29 };
30
31 struct message
32 {
33     struct message        *next;      /* next message in list */
34     struct message        *prev;      /* prev message in list */
35     int                    type;      /* message type (FIXME) */
36     handle_t               win;       /* window handle */
37     unsigned int           msg;       /* message code */
38     unsigned int           wparam;    /* parameters */
39     unsigned int           lparam;    /* parameters */
40     unsigned short         x;         /* x position */
41     unsigned short         y;         /* y position */
42     unsigned int           time;      /* message time */
43     unsigned int           info;      /* extra info */
44     struct message_result *result;    /* result in sender queue */
45 };
46
47 struct message_list
48 {
49     struct message *first;     /* head of list */
50     struct message *last;      /* tail of list */
51 };
52
53 struct timer
54 {
55     struct timer   *next;      /* next timer in list */
56     struct timer   *prev;      /* prev timer in list */
57     struct timeval  when;      /* next expiration */
58     unsigned int    rate;      /* timer rate in ms */
59     handle_t        win;       /* window handle */
60     unsigned int    msg;       /* message to post */
61     unsigned int    id;        /* timer id */
62     unsigned int    lparam;    /* lparam for message */
63 };
64
65 struct msg_queue
66 {
67     struct object          obj;           /* object header */
68     unsigned int           wake_bits;     /* wakeup bits */
69     unsigned int           wake_mask;     /* wakeup mask */
70     unsigned int           changed_bits;  /* changed wakeup bits */
71     unsigned int           changed_mask;  /* changed wakeup mask */
72     int                    paint_count;   /* pending paint messages count */
73     struct message_list    msg_list[NB_MSG_KINDS];  /* lists of messages */
74     struct message_result *send_result;   /* stack of sent messages waiting for result */
75     struct message_result *recv_result;   /* stack of received messages waiting for result */
76     struct message        *last_msg;      /* last msg returned to the app and not removed */
77     enum message_kind      last_msg_kind; /* message kind of last_msg */
78     struct timer          *first_timer;   /* head of timer list */
79     struct timer          *last_timer;    /* tail of timer list */
80     struct timer          *next_timer;    /* next timer to expire */
81     struct timeout_user   *timeout;       /* timeout for next timer to expire */
82 };
83
84 static void msg_queue_dump( struct object *obj, int verbose );
85 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry );
86 static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
87 static int msg_queue_signaled( struct object *obj, struct thread *thread );
88 static int msg_queue_satisfied( struct object *obj, struct thread *thread );
89 static void msg_queue_destroy( struct object *obj );
90 static void timer_callback( void *private );
91
92 static const struct object_ops msg_queue_ops =
93 {
94     sizeof(struct msg_queue),  /* size */
95     msg_queue_dump,            /* dump */
96     msg_queue_add_queue,       /* add_queue */
97     msg_queue_remove_queue,    /* remove_queue */
98     msg_queue_signaled,        /* signaled */
99     msg_queue_satisfied,       /* satisfied */
100     NULL,                      /* get_poll_events */
101     NULL,                      /* poll_event */
102     no_get_fd,                 /* get_fd */
103     no_flush,                  /* flush */
104     no_get_file_info,          /* get_file_info */
105     msg_queue_destroy          /* destroy */
106 };
107
108
109 static struct msg_queue *create_msg_queue( struct thread *thread )
110 {
111     struct msg_queue *queue;
112     int i;
113
114     if ((queue = alloc_object( &msg_queue_ops, -1 )))
115     {
116         queue->wake_bits       = 0;
117         queue->wake_mask       = 0;
118         queue->changed_bits    = 0;
119         queue->changed_mask    = 0;
120         queue->paint_count     = 0;
121         queue->send_result     = NULL;
122         queue->recv_result     = NULL;
123         queue->last_msg        = NULL;
124         queue->first_timer     = NULL;
125         queue->last_timer      = NULL;
126         queue->next_timer      = NULL;
127         queue->timeout         = NULL;
128         for (i = 0; i < NB_MSG_KINDS; i++)
129             queue->msg_list[i].first = queue->msg_list[i].last = NULL;
130
131         thread->queue = queue;
132         if (!thread->process->queue)
133             thread->process->queue = (struct msg_queue *)grab_object( queue );
134     }
135     return queue;
136 }
137
138 /* check the queue status */
139 inline static int is_signaled( struct msg_queue *queue )
140 {
141     return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
142 }
143
144 /* set/clear some queue bits */
145 inline static void change_queue_bits( struct msg_queue *queue, unsigned int set, unsigned int clear )
146 {
147     queue->wake_bits = (queue->wake_bits | set) & ~clear;
148     queue->changed_bits = (queue->changed_bits | set) & ~clear;
149     if (is_signaled( queue )) wake_up( &queue->obj, 0 );
150 }
151
152 /* get the QS_* bit corresponding to a given hardware message */
153 inline static int get_hardware_msg_bit( struct message *msg )
154 {
155     if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
156     if (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST) return QS_KEY;
157     return QS_MOUSEBUTTON;
158 }
159
160 /* get the current thread queue, creating it if needed */
161 inline struct msg_queue *get_current_queue(void)
162 {
163     struct msg_queue *queue = current->queue;
164     if (!queue) queue = create_msg_queue( current );
165     return queue;
166 }
167
168 /* append a message to the end of a list */
169 inline static void append_message( struct message_list *list, struct message *msg )
170 {
171     msg->next = NULL;
172     if ((msg->prev = list->last)) msg->prev->next = msg;
173     else list->first = msg;
174     list->last = msg;
175 }
176
177 /* unlink a message from a list it */
178 inline static void unlink_message( struct message_list *list, struct message *msg )
179 {
180     if (msg->next) msg->next->prev = msg->prev;
181     else list->last = msg->prev;
182     if (msg->prev) msg->prev->next = msg->next;
183     else list->first = msg->next;
184 }
185
186 /* free a message when deleting a queue or window */
187 static void free_message( struct message *msg )
188 {
189     struct message_result *result = msg->result;
190     if (result)
191     {
192         if (result->sender)
193         {
194             result->result   = 0;
195             result->error    = STATUS_ACCESS_DENIED;  /* FIXME */
196             result->replied  = 1;
197             result->receiver = NULL;
198             /* wake sender queue if waiting on this result */
199             if (result->sender->send_result == result)
200                 change_queue_bits( result->sender, QS_SMRESULT, 0 );
201         }
202         else free( result );
203     }
204     free( msg );
205 }
206
207 /* remove (and free) a message from a message list */
208 static void remove_queue_message( struct msg_queue *queue, struct message *msg,
209                                   enum message_kind kind )
210 {
211     int clr_bit;
212     struct message *other;
213
214     if (queue->last_msg == msg) queue->last_msg = NULL;
215     unlink_message( &queue->msg_list[kind], msg );
216     switch(kind)
217     {
218     case SEND_MESSAGE:
219         if (!queue->msg_list[kind].first) change_queue_bits( queue, 0, QS_SENDMESSAGE );
220         break;
221     case POST_MESSAGE:
222         if (!queue->msg_list[kind].first) change_queue_bits( queue, 0, QS_POSTMESSAGE );
223         break;
224     case COOKED_HW_MESSAGE:
225     case RAW_HW_MESSAGE:
226         clr_bit = get_hardware_msg_bit( msg );
227         for (other = queue->msg_list[kind].first; other; other = other->next)
228             if (get_hardware_msg_bit( other ) == clr_bit) break;
229         if (!other) change_queue_bits( queue, 0, clr_bit );
230         break;
231     }
232     free_message( msg );
233 }
234
235 /* send a message from the sender queue to the receiver queue */
236 static int send_message( struct msg_queue *send_queue, struct msg_queue *recv_queue,
237                          struct message *msg )
238 {
239     struct message_result *result = mem_alloc( sizeof(*result) );
240     if (!result) return 0;
241
242     /* put the result on the sender result stack */
243     result->sender    = send_queue;
244     result->receiver  = recv_queue;
245     result->replied   = 0;
246     result->send_next = send_queue->send_result;
247     send_queue->send_result = result;
248
249     /* and put the message on the receiver queue */
250     msg->result = result;
251     append_message( &recv_queue->msg_list[SEND_MESSAGE], msg );
252     change_queue_bits( recv_queue, QS_SENDMESSAGE, 0 );
253     return 1;
254 }
255
256 /* receive a message, removing it from the sent queue */
257 static void receive_message( struct msg_queue *queue, struct message *msg )
258 {
259     struct message_result *result = msg->result;
260
261     unlink_message( &queue->msg_list[SEND_MESSAGE], msg );
262     /* put the result on the receiver result stack */
263     result->recv_next  = queue->recv_result;
264     queue->recv_result = result;
265     free( msg );
266     if (!queue->msg_list[SEND_MESSAGE].first) change_queue_bits( queue, 0, QS_SENDMESSAGE );
267 }
268
269 /* set the result of the current received message */
270 static void reply_message( struct msg_queue *queue, unsigned int result,
271                            unsigned int error, int remove )
272 {
273     struct message_result *res = queue->recv_result;
274
275     if (remove)
276     {
277         queue->recv_result = res->recv_next;
278         res->receiver = NULL;
279         if (!res->sender)  /* no one waiting for it */
280         {
281             free( res );
282             return;
283         }
284     }
285     if (!res->replied)
286     {
287         res->result  = result;
288         res->error   = error;
289         res->replied = 1;
290         /* wake sender queue if waiting on this result */
291         if (res->sender && res->sender->send_result == res)
292             change_queue_bits( res->sender, QS_SMRESULT, 0 );
293     }
294 }
295
296 /* retrieve the reply of the current message being sent */
297 static unsigned int get_message_reply( struct msg_queue *queue, int cancel )
298 {
299     struct message_result *res = queue->send_result;
300     unsigned int ret = 0;
301
302     set_error( STATUS_PENDING );
303
304     if (res && (res->replied || cancel))
305     {
306         if (res->replied)
307         {
308             ret = res->result;
309             set_error( res->error );
310         }
311         queue->send_result = res->send_next;
312         res->sender = NULL;
313         if (!res->receiver) free( res );
314         if (!queue->send_result || !queue->send_result->replied)
315             change_queue_bits( queue, 0, QS_SMRESULT );
316     }
317     return ret;
318 }
319
320 /* empty a message list and free all the messages */
321 static void empty_msg_list( struct message_list *list )
322 {
323     struct message *msg = list->first;
324     while (msg)
325     {
326         struct message *next = msg->next;
327         free_message( msg );
328         msg = next;
329     }
330 }
331
332 /* cleanup all pending results when deleting a queue */
333 static void cleanup_results( struct msg_queue *queue )
334 {
335     struct message_result *result, *next;
336
337     result = queue->send_result;
338     while (result)
339     {
340         next = result->send_next;
341         result->sender = NULL;
342         if (!result->receiver) free( result );
343         result = next;
344     }
345
346     while (queue->recv_result) reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1 );
347 }
348
349 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
350 {
351     struct msg_queue *queue = (struct msg_queue *)obj;
352     struct process *process = entry->thread->process;
353
354     /* a thread can only wait on its own queue */
355     if (entry->thread->queue != queue)
356     {
357         set_error( STATUS_ACCESS_DENIED );
358         return 0;
359     }
360     /* if waiting on the main process queue, set the idle event */
361     if (process->queue == queue)
362     {
363         if (process->idle_event) set_event( process->idle_event );
364     }
365     add_queue( obj, entry );
366     return 1;
367 }
368
369 static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *entry )
370 {
371     struct msg_queue *queue = (struct msg_queue *)obj;
372     struct process *process = entry->thread->process;
373
374     remove_queue( obj, entry );
375
376     assert( entry->thread->queue == queue );
377
378     /* if waiting on the main process queue, reset the idle event */
379     if (process->queue == queue)
380     {
381         if (process->idle_event) reset_event( process->idle_event );
382     }
383 }
384
385 static void msg_queue_dump( struct object *obj, int verbose )
386 {
387     struct msg_queue *queue = (struct msg_queue *)obj;
388     fprintf( stderr, "Msg queue bits=%x mask=%x\n",
389              queue->wake_bits, queue->wake_mask );
390 }
391
392 static int msg_queue_signaled( struct object *obj, struct thread *thread )
393 {
394     struct msg_queue *queue = (struct msg_queue *)obj;
395     return is_signaled( queue );
396 }
397
398 static int msg_queue_satisfied( struct object *obj, struct thread *thread )
399 {
400     struct msg_queue *queue = (struct msg_queue *)obj;
401     queue->wake_mask = 0;
402     queue->changed_mask = 0;
403     return 0;  /* Not abandoned */
404 }
405
406 static void msg_queue_destroy( struct object *obj )
407 {
408     struct msg_queue *queue = (struct msg_queue *)obj;
409     struct timer *timer = queue->first_timer;
410     int i;
411
412     cleanup_results( queue );
413     for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
414
415     while (timer)
416     {
417         struct timer *next = timer->next;
418         free( timer );
419         timer = next;
420     }
421     if (queue->timeout) remove_timeout_user( queue->timeout );
422 }
423
424 /* set the next timer to expire */
425 static void set_next_timer( struct msg_queue *queue, struct timer *timer )
426 {
427     if (queue->timeout)
428     {
429         remove_timeout_user( queue->timeout );
430         queue->timeout = NULL;
431     }
432     if ((queue->next_timer = timer))
433         queue->timeout = add_timeout_user( &timer->when, timer_callback, queue );
434
435     /* set/clear QS_TIMER bit */
436     if (queue->next_timer == queue->first_timer)
437         change_queue_bits( queue, 0, QS_TIMER );
438     else
439         change_queue_bits( queue, QS_TIMER, 0 );
440 }
441
442 /* callback for the next timer expiration */
443 static void timer_callback( void *private )
444 {
445     struct msg_queue *queue = private;
446
447     queue->timeout = NULL;
448     /* move on to the next timer */
449     set_next_timer( queue, queue->next_timer->next );
450 }
451
452 /* link a timer at its rightful place in the queue list */
453 static void link_timer( struct msg_queue *queue, struct timer *timer )
454 {
455     struct timer *pos = queue->next_timer;
456
457     while (pos && time_before( &pos->when, &timer->when )) pos = pos->next;
458
459     if (pos) /* insert before pos */
460     {
461         if ((timer->prev = pos->prev)) timer->prev->next = timer;
462         else queue->first_timer = timer;
463         timer->next = pos;
464         pos->prev = timer;
465     }
466     else  /* insert at end */
467     {
468         timer->next = NULL;
469         timer->prev = queue->last_timer;
470         if (queue->last_timer) queue->last_timer->next = timer;
471         else queue->first_timer = timer;
472         queue->last_timer = timer;
473     }
474     /* check if we replaced the next timer */
475     if (pos == queue->next_timer) set_next_timer( queue, timer );
476 }
477
478 /* remove a timer from the queue timer list */
479 static void unlink_timer( struct msg_queue *queue, struct timer *timer )
480 {
481     if (timer->next) timer->next->prev = timer->prev;
482     else queue->last_timer = timer->prev;
483     if (timer->prev) timer->prev->next = timer->next;
484     else queue->first_timer = timer->next;
485     /* check if we removed the next timer */
486     if (queue->next_timer == timer) set_next_timer( queue, timer->next );
487     else if (queue->next_timer == queue->first_timer) change_queue_bits( queue, 0, QS_TIMER );
488 }
489
490 /* restart an expired timer */
491 static void restart_timer( struct msg_queue *queue, struct timer *timer )
492 {
493     struct timeval now;
494     unlink_timer( queue, timer );
495     gettimeofday( &now, 0 );
496     while (!time_before( &now, &timer->when )) add_timeout( &timer->when, timer->rate );
497     link_timer( queue, timer );
498 }
499
500 /* find an expired timer matching the filtering parameters */
501 static struct timer *find_expired_timer( struct msg_queue *queue, handle_t win,
502                                          unsigned int get_first, unsigned int get_last,
503                                          int remove )
504 {
505     struct timer *timer;
506     for (timer = queue->first_timer; (timer && timer != queue->next_timer); timer = timer->next)
507     {
508         if (win && timer->win != win) continue;
509         if (timer->msg >= get_first && timer->msg <= get_last)
510         {
511             if (remove) restart_timer( queue, timer );
512             return timer;
513         }
514     }
515     return NULL;
516 }
517
518 /* kill a timer */
519 static int kill_timer( struct msg_queue *queue, handle_t win, unsigned int msg, unsigned int id )
520 {
521     struct timer *timer;
522
523     for (timer = queue->first_timer; timer; timer = timer->next)
524     {
525         if (timer->win != win || timer->msg != msg || timer->id != id) continue;
526         unlink_timer( queue, timer );
527         free( timer );
528         return 1;
529     }
530     return 0;
531 }
532
533 /* add a timer */
534 static struct timer *set_timer( struct msg_queue *queue, unsigned int rate )
535 {
536     struct timer *timer = mem_alloc( sizeof(*timer) );
537     if (timer)
538     {
539         timer->rate  = rate;
540         gettimeofday( &timer->when, 0 );
541         add_timeout( &timer->when, rate );
542         link_timer( queue, timer );
543     }
544     return timer;
545 }
546
547 /* remove all messages and timers belonging to a certain window */
548 static void cleanup_window( struct msg_queue *queue, handle_t win )
549 {
550     struct timer *timer;
551     struct message *msg;
552     int i;
553
554     /* remove timers */
555     timer = queue->first_timer;
556     while (timer)
557     {
558         struct timer *next = timer->next;
559         if (timer->win == win)
560         {
561             unlink_timer( queue, timer );
562             free( timer );
563         }
564         timer = next;
565     }
566
567     /* remove messages */
568     for (i = 0; i < NB_MSG_KINDS; i++)
569     {
570         msg = queue->msg_list[i].first;
571         while (msg)
572         {
573             struct message *next = msg->next;
574             if (msg->win == win) remove_queue_message( queue, msg, i );
575             msg = next;
576         }
577     }
578 }
579
580 /* get the message queue of the current thread */
581 DECL_HANDLER(get_msg_queue)
582 {
583     struct msg_queue *queue = get_current_queue();
584
585     req->handle = 0;
586     if (queue) req->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
587 }
588
589
590 /* increment the message queue paint count */
591 DECL_HANDLER(inc_queue_paint_count)
592 {
593     struct msg_queue *queue;
594     struct thread *thread = get_thread_from_id( req->id );
595
596     if (!thread) return;
597
598     if ((queue = thread->queue))
599     {
600         if ((queue->paint_count += req->incr) < 0) queue->paint_count = 0;
601
602         if (queue->paint_count)
603             change_queue_bits( queue, QS_PAINT, 0 );
604         else
605             change_queue_bits( queue, 0, QS_PAINT );
606     }
607     else set_error( STATUS_INVALID_PARAMETER );
608
609     release_object( thread );
610
611 }
612
613
614 /* set the current message queue wakeup mask */
615 DECL_HANDLER(set_queue_mask)
616 {
617     struct msg_queue *queue = get_current_queue();
618
619     if (queue)
620     {
621         queue->wake_mask    = req->wake_mask;
622         queue->changed_mask = req->changed_mask;
623         req->wake_bits      = queue->wake_bits;
624         req->changed_bits   = queue->changed_bits;
625         if (is_signaled( queue ))
626         {
627             /* if skip wait is set, do what would have been done in the subsequent wait */
628             if (req->skip_wait) msg_queue_satisfied( &queue->obj, current );
629             else wake_up( &queue->obj, 0 );
630         }
631     }
632 }
633
634
635 /* get the current message queue status */
636 DECL_HANDLER(get_queue_status)
637 {
638     struct msg_queue *queue = current->queue;
639     if (queue)
640     {
641         req->wake_bits    = queue->wake_bits;
642         req->changed_bits = queue->changed_bits;
643         if (req->clear) queue->changed_bits = 0;
644     }
645     else req->wake_bits = req->changed_bits = 0;
646 }
647
648
649 /* send a message to a thread queue */
650 DECL_HANDLER(send_message)
651 {
652     struct message *msg;
653     struct msg_queue *send_queue = get_current_queue();
654     struct msg_queue *recv_queue;
655     struct thread *thread = get_thread_from_id( req->id );
656
657     if (!thread) return;
658
659     if (!(recv_queue = thread->queue))
660     {
661         set_error( STATUS_INVALID_PARAMETER );
662         release_object( thread );
663         return;
664     }
665
666     if ((msg = mem_alloc( sizeof(*msg) )))
667     {
668         msg->type    = req->type;
669         msg->win     = req->win;
670         msg->msg     = req->msg;
671         msg->wparam  = req->wparam;
672         msg->lparam  = req->lparam;
673         msg->x       = req->x;
674         msg->y       = req->y;
675         msg->time    = req->time;
676         msg->info    = req->info;
677         msg->result  = NULL;
678         switch(req->kind)
679         {
680         case SEND_MESSAGE:
681             send_message( send_queue, recv_queue, msg );
682             break;
683         case POST_MESSAGE:
684             append_message( &recv_queue->msg_list[POST_MESSAGE], msg );
685             change_queue_bits( recv_queue, QS_POSTMESSAGE, 0 );
686             break;
687         case COOKED_HW_MESSAGE:
688         case RAW_HW_MESSAGE:
689             append_message( &recv_queue->msg_list[req->kind], msg );
690             change_queue_bits( recv_queue, get_hardware_msg_bit(msg), 0 );
691             break;
692         default:
693             free( msg );
694             set_error( STATUS_INVALID_PARAMETER );
695             break;
696         }
697     }
698     release_object( thread );
699 }
700
701 /* store a message contents into the request buffer; helper for get_message */
702 inline static void put_req_message( struct get_message_request *req, const struct message *msg )
703 {
704     req->type   = msg->type;
705     req->win    = msg->win;
706     req->msg    = msg->msg;
707     req->wparam = msg->wparam;
708     req->lparam = msg->lparam;
709     req->x      = msg->x;
710     req->y      = msg->y;
711     req->time   = msg->time;
712     req->info   = msg->info;
713 }
714
715 /* return a message to the application, removing it from the queue if needed */
716 static void return_message_to_app( struct msg_queue *queue, struct get_message_request *req,
717                                    struct message *msg, enum message_kind kind )
718 {
719     req->kind = kind;
720     put_req_message( req, msg );
721     /* raw messages always get removed */
722     if ((kind == RAW_HW_MESSAGE) || (req->flags & GET_MSG_REMOVE))
723     {
724         queue->last_msg = NULL;
725         remove_queue_message( queue, msg, kind );
726     }
727     else  /* remember it as the last returned message */
728     {
729         queue->last_msg = msg;
730         queue->last_msg_kind = kind;
731     }
732 }
733
734
735 inline static struct message *find_matching_message( const struct message_list *list, handle_t win,
736                                                      unsigned int first, unsigned int last )
737 {
738     struct message *msg;
739
740     for (msg = list->first; msg; msg = msg->next)
741     {
742         /* check against the filters */
743         if (msg->msg == WM_QUIT) break;  /* WM_QUIT is never filtered */
744         if (win && msg->win && msg->win != win) continue;
745         if (msg->msg < first) continue;
746         if (msg->msg > last) continue;
747         break; /* found one */
748     }
749     return msg;
750 }
751
752
753 /* get a message from the current queue */
754 DECL_HANDLER(get_message)
755 {
756     struct timer *timer;
757     struct message *msg;
758     struct msg_queue *queue = get_current_queue();
759
760     if (!queue) return;
761
762     /* first check for sent messages */
763     if ((msg = queue->msg_list[SEND_MESSAGE].first))
764     {
765         req->kind = SEND_MESSAGE;
766         put_req_message( req, msg );
767         receive_message( queue, msg );
768         return;
769     }
770     if (req->flags & GET_MSG_SENT_ONLY) goto done;  /* nothing else to check */
771
772     /* if requested, remove the last returned but not yet removed message */
773     if ((req->flags & GET_MSG_REMOVE_LAST) && queue->last_msg)
774         remove_queue_message( queue, queue->last_msg, queue->last_msg_kind );
775     queue->last_msg = NULL;
776
777     /* clear changed bits so we can wait on them if we don't find a message */
778     queue->changed_bits = 0;
779
780     /* then check for posted messages */
781     if ((msg = find_matching_message( &queue->msg_list[POST_MESSAGE], req->get_win,
782                                       req->get_first, req->get_last )))
783     {
784         return_message_to_app( queue, req, msg, POST_MESSAGE );
785         return;
786     }
787
788     /* then check for cooked hardware messages */
789     if ((msg = find_matching_message( &queue->msg_list[COOKED_HW_MESSAGE], req->get_win,
790                                       req->get_first, req->get_last )))
791     {
792         return_message_to_app( queue, req, msg, COOKED_HW_MESSAGE );
793         return;
794     }
795
796     /* then check for any raw hardware message */
797     if ((msg = queue->msg_list[RAW_HW_MESSAGE].first))
798     {
799         return_message_to_app( queue, req, msg, RAW_HW_MESSAGE );
800         return;
801     }
802
803     /* now check for WM_PAINT */
804     if ((queue->wake_bits & QS_PAINT) &&
805         (WM_PAINT >= req->get_first) && (WM_PAINT <= req->get_last))
806     {
807         req->kind   = POST_MESSAGE;
808         req->type   = 0;
809         req->win    = 0;
810         req->msg    = WM_PAINT;
811         req->wparam = 0;
812         req->lparam = 0;
813         req->x      = 0;
814         req->y      = 0;
815         req->time   = 0;
816         req->info   = 0;
817         return;
818     }
819
820     /* now check for timer */
821     if ((timer = find_expired_timer( queue, req->get_win, req->get_first,
822                                      req->get_last, (req->flags & GET_MSG_REMOVE) )))
823     {
824         req->kind   = POST_MESSAGE;
825         req->type   = 0;
826         req->win    = timer->win;
827         req->msg    = timer->msg;
828         req->wparam = timer->id;
829         req->lparam = timer->lparam;
830         req->x      = 0;
831         req->y      = 0;
832         req->time   = 0;
833         req->info   = 0;
834         return;
835     }
836
837  done:
838     set_error( STATUS_PENDING );  /* FIXME */
839 }
840
841
842 /* reply to a sent message */
843 DECL_HANDLER(reply_message)
844 {
845     if (current->queue && current->queue->recv_result)
846         reply_message( current->queue, req->result, 0, req->remove );
847     else
848         set_error( STATUS_ACCESS_DENIED );
849 }
850
851
852 /* retrieve the reply for the last message sent */
853 DECL_HANDLER(get_message_reply)
854 {
855     if (current->queue) req->result = get_message_reply( current->queue, req->cancel );
856     else set_error( STATUS_ACCESS_DENIED );
857 }
858
859
860 /* check if we are processing a sent message */
861 DECL_HANDLER(in_send_message)
862 {
863     int flags = 0;
864
865     if (current->queue)
866     {
867         struct message_result *result = current->queue->recv_result;
868         if (result)
869         {
870             flags |= ISMEX_SEND;  /* FIXME */
871             if (result->replied || !result->sender) flags |= ISMEX_REPLIED;
872         }
873     }
874     req->flags = flags;
875 }
876
877
878 /* cleanup a queue when a window is deleted */
879 DECL_HANDLER(cleanup_window_queue)
880 {
881     if (current->queue) cleanup_window( current->queue, req->win );
882 }
883
884
885 /* set a window timer */
886 DECL_HANDLER(set_win_timer)
887 {
888     struct timer *timer;
889     struct msg_queue *queue = get_current_queue();
890
891     if (!queue) return;
892
893     /* remove it if it existed already */
894     if (req->win) kill_timer( queue, req->win, req->msg, req->id );
895
896     if ((timer = set_timer( queue, req->rate )))
897     {
898         timer->win    = req->win;
899         timer->msg    = req->msg;
900         timer->id     = req->id;
901         timer->lparam = req->lparam;
902     }
903 }
904
905 /* kill a window timer */
906 DECL_HANDLER(kill_win_timer)
907 {
908     struct msg_queue *queue = current->queue;
909
910     if (!queue || !kill_timer( queue, req->win, req->msg, req->id ))
911         set_error( STATUS_INVALID_PARAMETER );
912 }