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