blob: e250faecb4e473ffea0b7576668f329cf2539d4f [file] [log] [blame]
Alexandre Julliardc5e433a2000-05-30 19:48:18 +00001/*
2 * Server-side message queues
3 *
4 * Copyright (C) 2000 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliardc5e433a2000-05-30 19:48:18 +000019 */
20
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000021#include "config.h"
22#include "wine/port.h"
23
Alexandre Julliardc5e433a2000-05-30 19:48:18 +000024#include <assert.h>
25#include <stdio.h>
26#include <stdlib.h>
27
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000028#include "winbase.h"
29#include "wingdi.h"
30#include "winuser.h"
31
Alexandre Julliardc5e433a2000-05-30 19:48:18 +000032#include "handle.h"
33#include "thread.h"
34#include "process.h"
35#include "request.h"
Alexandre Julliard1a66d222001-08-28 18:44:52 +000036#include "user.h"
Alexandre Julliardc5e433a2000-05-30 19:48:18 +000037
Alexandre Julliardd253c582001-08-07 19:19:08 +000038enum message_kind { SEND_MESSAGE, POST_MESSAGE, COOKED_HW_MESSAGE, RAW_HW_MESSAGE };
39#define NB_MSG_KINDS (RAW_HW_MESSAGE+1)
40
41
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000042struct message_result
43{
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 */
Alexandre Julliardd253c582001-08-07 19:19:08 +000051 void *data; /* message reply data */
52 unsigned int data_size; /* size of message reply data */
53 struct timeout_user *timeout; /* result timeout */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000054};
55
56struct message
57{
58 struct message *next; /* next message in list */
59 struct message *prev; /* prev message in list */
Alexandre Julliardd253c582001-08-07 19:19:08 +000060 enum message_type type; /* message type */
Alexandre Julliard1a66d222001-08-28 18:44:52 +000061 user_handle_t win; /* window handle */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000062 unsigned int msg; /* message code */
63 unsigned int wparam; /* parameters */
64 unsigned int lparam; /* parameters */
Alexandre Julliardd253c582001-08-07 19:19:08 +000065 int x; /* x position */
66 int y; /* y position */
Alexandre Julliard838d65a2001-06-19 19:16:41 +000067 unsigned int time; /* message time */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000068 unsigned int info; /* extra info */
Alexandre Julliardd253c582001-08-07 19:19:08 +000069 void *data; /* message data for sent messages */
70 unsigned int data_size; /* size of message data */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000071 struct message_result *result; /* result in sender queue */
72};
73
74struct message_list
75{
76 struct message *first; /* head of list */
77 struct message *last; /* tail of list */
78};
79
80struct timer
81{
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 */
Alexandre Julliard1a66d222001-08-28 18:44:52 +000086 user_handle_t win; /* window handle */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000087 unsigned int msg; /* message to post */
88 unsigned int id; /* timer id */
89 unsigned int lparam; /* lparam for message */
90};
91
Alexandre Julliardc5e433a2000-05-30 19:48:18 +000092struct msg_queue
93{
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000094 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 */
Alexandre Julliard4b0343d2001-06-20 22:55:31 +000099 int paint_count; /* pending paint messages count */
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000100 struct message_list msg_list[NB_MSG_KINDS]; /* lists of messages */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000101 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 */
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000103 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 */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000105 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 */
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000109};
110
111static void msg_queue_dump( struct object *obj, int verbose );
112static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry );
113static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
114static int msg_queue_signaled( struct object *obj, struct thread *thread );
115static int msg_queue_satisfied( struct object *obj, struct thread *thread );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000116static void msg_queue_destroy( struct object *obj );
117static void timer_callback( void *private );
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000118
119static const struct object_ops msg_queue_ops =
120{
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 */
Alexandre Julliard1ab243b2000-12-19 02:12:45 +0000129 no_get_fd, /* get_fd */
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000130 no_flush, /* flush */
131 no_get_file_info, /* get_file_info */
Mike McCormack6f011c02001-12-20 00:07:05 +0000132 NULL, /* queue_async */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000133 msg_queue_destroy /* destroy */
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000134};
135
136
137static struct msg_queue *create_msg_queue( struct thread *thread )
138{
139 struct msg_queue *queue;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000140 int i;
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000141
142 if ((queue = alloc_object( &msg_queue_ops, -1 )))
143 {
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000144 queue->wake_bits = 0;
145 queue->wake_mask = 0;
146 queue->changed_bits = 0;
147 queue->changed_mask = 0;
Alexandre Julliard4b0343d2001-06-20 22:55:31 +0000148 queue->paint_count = 0;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000149 queue->send_result = NULL;
150 queue->recv_result = NULL;
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000151 queue->last_msg = NULL;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000152 queue->first_timer = NULL;
153 queue->last_timer = NULL;
154 queue->next_timer = NULL;
155 queue->timeout = NULL;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000156 for (i = 0; i < NB_MSG_KINDS; i++)
157 queue->msg_list[i].first = queue->msg_list[i].last = NULL;
158
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000159 thread->queue = queue;
160 if (!thread->process->queue)
161 thread->process->queue = (struct msg_queue *)grab_object( queue );
162 }
163 return queue;
164}
165
Alexandre Julliard31022d62002-08-16 23:30:41 +0000166/* free the message queue of a thread at thread exit */
167void free_msg_queue( struct thread *thread )
168{
169 struct process *process = thread->process;
170
171 if (!thread->queue) return;
172 if (process->queue == thread->queue) /* is it the process main queue? */
173 {
174 release_object( process->queue );
175 process->queue = NULL;
176 if (process->idle_event)
177 {
178 set_event( process->idle_event );
179 release_object( process->idle_event );
180 process->idle_event = NULL;
181 }
182 }
183 release_object( thread->queue );
184 thread->queue = NULL;
185}
186
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000187/* check the queue status */
188inline static int is_signaled( struct msg_queue *queue )
189{
190 return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
191}
192
Alexandre Julliardd253c582001-08-07 19:19:08 +0000193/* set some queue bits */
194inline static void set_queue_bits( struct msg_queue *queue, unsigned int bits )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000195{
Alexandre Julliardd253c582001-08-07 19:19:08 +0000196 queue->wake_bits |= bits;
197 queue->changed_bits |= bits;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000198 if (is_signaled( queue )) wake_up( &queue->obj, 0 );
199}
200
Alexandre Julliardd253c582001-08-07 19:19:08 +0000201/* clear some queue bits */
202inline static void clear_queue_bits( struct msg_queue *queue, unsigned int bits )
203{
204 queue->wake_bits &= ~bits;
205 queue->changed_bits &= ~bits;
206}
207
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000208/* get the QS_* bit corresponding to a given hardware message */
209inline static int get_hardware_msg_bit( struct message *msg )
210{
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;
214}
215
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000216/* get the current thread queue, creating it if needed */
Alexandre Julliard805bdc52001-11-13 22:23:48 +0000217inline static struct msg_queue *get_current_queue(void)
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000218{
219 struct msg_queue *queue = current->queue;
220 if (!queue) queue = create_msg_queue( current );
221 return queue;
222}
223
224/* append a message to the end of a list */
225inline static void append_message( struct message_list *list, struct message *msg )
226{
227 msg->next = NULL;
228 if ((msg->prev = list->last)) msg->prev->next = msg;
229 else list->first = msg;
230 list->last = msg;
231}
232
233/* unlink a message from a list it */
234inline static void unlink_message( struct message_list *list, struct message *msg )
235{
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;
240}
241
Alexandre Julliarde630aa02001-07-11 17:29:01 +0000242/* try to merge a message with the last in the list; return 1 if successful */
243static int merge_message( struct message_list *list, const struct message *msg )
244{
245 struct message *prev = list->last;
246
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;
260}
261
Alexandre Julliardd253c582001-08-07 19:19:08 +0000262/* free a result structure */
263static void free_result( struct message_result *result )
264{
265 if (result->timeout) remove_timeout_user( result->timeout );
266 if (result->data) free( result->data );
267 free( result );
268}
269
270/* store the message result in the appropriate structure */
271static void store_message_result( struct message_result *res, unsigned int result,
272 unsigned int error )
273{
274 res->result = result;
275 res->error = error;
276 res->replied = 1;
277 if (res->timeout)
278 {
279 remove_timeout_user( res->timeout );
280 res->timeout = NULL;
281 }
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 );
285}
286
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000287/* free a message when deleting a queue or window */
288static void free_message( struct message *msg )
289{
290 struct message_result *result = msg->result;
291 if (result)
292 {
293 if (result->sender)
294 {
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000295 result->receiver = NULL;
Alexandre Julliardd253c582001-08-07 19:19:08 +0000296 store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000297 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000298 else free_result( result );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000299 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000300 if (msg->data) free( msg->data );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000301 free( msg );
302}
303
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000304/* remove (and free) a message from a message list */
305static void remove_queue_message( struct msg_queue *queue, struct message *msg,
306 enum message_kind kind )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000307{
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000308 int clr_bit;
309 struct message *other;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000310
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000311 if (queue->last_msg == msg) queue->last_msg = NULL;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000312 unlink_message( &queue->msg_list[kind], msg );
313 switch(kind)
314 {
315 case SEND_MESSAGE:
Alexandre Julliardd253c582001-08-07 19:19:08 +0000316 if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_SENDMESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000317 break;
318 case POST_MESSAGE:
Alexandre Julliardd253c582001-08-07 19:19:08 +0000319 if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_POSTMESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000320 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;
Alexandre Julliardd253c582001-08-07 19:19:08 +0000326 if (!other) clear_queue_bits( queue, clr_bit );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000327 break;
328 }
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000329 free_message( msg );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000330}
331
Alexandre Julliardd253c582001-08-07 19:19:08 +0000332/* message timed out without getting a reply */
333static void result_timeout( void *private )
334{
335 struct message_result *result = private;
336
337 assert( !result->replied );
338
339 result->timeout = NULL;
340 store_message_result( result, 0, STATUS_TIMEOUT );
341}
342
343/* allocate and fill a message result structure */
344static struct message_result *alloc_message_result( struct msg_queue *send_queue,
345 struct msg_queue *recv_queue,
346 unsigned int timeout )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000347{
348 struct message_result *result = mem_alloc( sizeof(*result) );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000349 if (result)
350 {
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)
361 {
362 struct timeval when;
363 gettimeofday( &when, 0 );
364 add_timeout( &when, timeout );
365 result->timeout = add_timeout_user( &when, result_timeout, result );
366 }
367 }
368 return result;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000369}
370
371/* receive a message, removing it from the sent queue */
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000372static void receive_message( struct msg_queue *queue, struct message *msg,
373 struct get_message_reply *reply )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000374{
375 struct message_result *result = msg->result;
376
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000377 reply->total = msg->data_size;
378 if (msg->data_size > get_reply_max_size())
379 {
380 set_error( STATUS_BUFFER_OVERFLOW );
381 return;
382 }
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;
392
393 if (msg->data) set_reply_data_ptr( msg->data, msg->data_size );
394
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000395 unlink_message( &queue->msg_list[SEND_MESSAGE], msg );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000396 /* put the result on the receiver result stack */
Alexandre Julliardd253c582001-08-07 19:19:08 +0000397 if (result)
398 {
399 result->recv_next = queue->recv_result;
400 queue->recv_result = result;
401 }
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000402 free( msg );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000403 if (!queue->msg_list[SEND_MESSAGE].first) clear_queue_bits( queue, QS_SENDMESSAGE );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000404}
405
406/* set the result of the current received message */
407static void reply_message( struct msg_queue *queue, unsigned int result,
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000408 unsigned int error, int remove, const void *data, size_t len )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000409{
410 struct message_result *res = queue->recv_result;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000411
412 if (remove)
413 {
414 queue->recv_result = res->recv_next;
415 res->receiver = NULL;
416 if (!res->sender) /* no one waiting for it */
417 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000418 free_result( res );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000419 return;
420 }
421 }
422 if (!res->replied)
423 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000424 if (len && (res->data = memdup( data, len ))) res->data_size = len;
425 store_message_result( res, result, error );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000426 }
427}
428
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000429/* empty a message list and free all the messages */
430static void empty_msg_list( struct message_list *list )
431{
432 struct message *msg = list->first;
433 while (msg)
434 {
435 struct message *next = msg->next;
436 free_message( msg );
437 msg = next;
438 }
439}
440
441/* cleanup all pending results when deleting a queue */
442static void cleanup_results( struct msg_queue *queue )
443{
444 struct message_result *result, *next;
445
446 result = queue->send_result;
447 while (result)
448 {
449 next = result->send_next;
450 result->sender = NULL;
Alexandre Julliardd253c582001-08-07 19:19:08 +0000451 if (!result->receiver) free_result( result );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000452 result = next;
453 }
454
Alexandre Julliardd253c582001-08-07 19:19:08 +0000455 while (queue->recv_result)
456 reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000457}
458
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000459static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
460{
461 struct msg_queue *queue = (struct msg_queue *)obj;
462 struct process *process = entry->thread->process;
463
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000464 /* a thread can only wait on its own queue */
465 if (entry->thread->queue != queue)
466 {
467 set_error( STATUS_ACCESS_DENIED );
468 return 0;
469 }
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000470 /* if waiting on the main process queue, set the idle event */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000471 if (process->queue == queue)
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000472 {
473 if (process->idle_event) set_event( process->idle_event );
474 }
475 add_queue( obj, entry );
476 return 1;
477}
478
479static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *entry )
480{
481 struct msg_queue *queue = (struct msg_queue *)obj;
482 struct process *process = entry->thread->process;
483
484 remove_queue( obj, entry );
485
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000486 assert( entry->thread->queue == queue );
487
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000488 /* if waiting on the main process queue, reset the idle event */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000489 if (process->queue == queue)
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000490 {
491 if (process->idle_event) reset_event( process->idle_event );
492 }
493}
494
495static void msg_queue_dump( struct object *obj, int verbose )
496{
497 struct msg_queue *queue = (struct msg_queue *)obj;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000498 fprintf( stderr, "Msg queue bits=%x mask=%x\n",
499 queue->wake_bits, queue->wake_mask );
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000500}
501
502static int msg_queue_signaled( struct object *obj, struct thread *thread )
503{
504 struct msg_queue *queue = (struct msg_queue *)obj;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000505 return is_signaled( queue );
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000506}
507
508static int msg_queue_satisfied( struct object *obj, struct thread *thread )
509{
510 struct msg_queue *queue = (struct msg_queue *)obj;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000511 queue->wake_mask = 0;
512 queue->changed_mask = 0;
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000513 return 0; /* Not abandoned */
514}
515
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000516static void msg_queue_destroy( struct object *obj )
517{
518 struct msg_queue *queue = (struct msg_queue *)obj;
519 struct timer *timer = queue->first_timer;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000520 int i;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000521
522 cleanup_results( queue );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000523 for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000524
525 while (timer)
526 {
527 struct timer *next = timer->next;
528 free( timer );
529 timer = next;
530 }
531 if (queue->timeout) remove_timeout_user( queue->timeout );
532}
533
534/* set the next timer to expire */
535static void set_next_timer( struct msg_queue *queue, struct timer *timer )
536{
537 if (queue->timeout)
538 {
539 remove_timeout_user( queue->timeout );
540 queue->timeout = NULL;
541 }
542 if ((queue->next_timer = timer))
543 queue->timeout = add_timeout_user( &timer->when, timer_callback, queue );
544
545 /* set/clear QS_TIMER bit */
546 if (queue->next_timer == queue->first_timer)
Alexandre Julliardd253c582001-08-07 19:19:08 +0000547 clear_queue_bits( queue, QS_TIMER );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000548 else
Alexandre Julliardd253c582001-08-07 19:19:08 +0000549 set_queue_bits( queue, QS_TIMER );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000550}
551
552/* callback for the next timer expiration */
553static void timer_callback( void *private )
554{
555 struct msg_queue *queue = private;
556
557 queue->timeout = NULL;
558 /* move on to the next timer */
559 set_next_timer( queue, queue->next_timer->next );
560}
561
562/* link a timer at its rightful place in the queue list */
563static void link_timer( struct msg_queue *queue, struct timer *timer )
564{
565 struct timer *pos = queue->next_timer;
566
567 while (pos && time_before( &pos->when, &timer->when )) pos = pos->next;
568
569 if (pos) /* insert before pos */
570 {
571 if ((timer->prev = pos->prev)) timer->prev->next = timer;
572 else queue->first_timer = timer;
573 timer->next = pos;
574 pos->prev = timer;
575 }
576 else /* insert at end */
577 {
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;
583 }
584 /* check if we replaced the next timer */
585 if (pos == queue->next_timer) set_next_timer( queue, timer );
586}
587
588/* remove a timer from the queue timer list */
589static void unlink_timer( struct msg_queue *queue, struct timer *timer )
590{
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 );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000597 else if (queue->next_timer == queue->first_timer) clear_queue_bits( queue, QS_TIMER );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000598}
599
600/* restart an expired timer */
601static void restart_timer( struct msg_queue *queue, struct timer *timer )
602{
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 );
608}
609
610/* find an expired timer matching the filtering parameters */
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000611static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t win,
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000612 unsigned int get_first, unsigned int get_last,
613 int remove )
614{
615 struct timer *timer;
616 for (timer = queue->first_timer; (timer && timer != queue->next_timer); timer = timer->next)
617 {
618 if (win && timer->win != win) continue;
619 if (timer->msg >= get_first && timer->msg <= get_last)
620 {
621 if (remove) restart_timer( queue, timer );
622 return timer;
623 }
624 }
625 return NULL;
626}
627
628/* kill a timer */
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000629static int kill_timer( struct msg_queue *queue, user_handle_t win,
630 unsigned int msg, unsigned int id )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000631{
632 struct timer *timer;
633
634 for (timer = queue->first_timer; timer; timer = timer->next)
635 {
636 if (timer->win != win || timer->msg != msg || timer->id != id) continue;
637 unlink_timer( queue, timer );
638 free( timer );
639 return 1;
640 }
641 return 0;
642}
643
644/* add a timer */
645static struct timer *set_timer( struct msg_queue *queue, unsigned int rate )
646{
647 struct timer *timer = mem_alloc( sizeof(*timer) );
648 if (timer)
649 {
650 timer->rate = rate;
651 gettimeofday( &timer->when, 0 );
652 add_timeout( &timer->when, rate );
653 link_timer( queue, timer );
654 }
655 return timer;
656}
657
Alexandre Julliard805bdc52001-11-13 22:23:48 +0000658
659/* increment (or decrement if 'incr' is negative) the queue paint count */
660void inc_queue_paint_count( struct thread *thread, int incr )
661{
662 struct msg_queue *queue = thread->queue;
663
664 assert( queue );
665
666 if ((queue->paint_count += incr) < 0) queue->paint_count = 0;
667
668 if (queue->paint_count)
669 set_queue_bits( queue, QS_PAINT );
670 else
671 clear_queue_bits( queue, QS_PAINT );
672}
673
674
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000675/* remove all messages and timers belonging to a certain window */
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000676void queue_cleanup_window( struct thread *thread, user_handle_t win )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000677{
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000678 struct msg_queue *queue = thread->queue;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000679 struct timer *timer;
680 struct message *msg;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000681 int i;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000682
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000683 if (!queue) return;
684
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000685 /* remove timers */
686 timer = queue->first_timer;
687 while (timer)
688 {
689 struct timer *next = timer->next;
690 if (timer->win == win)
691 {
692 unlink_timer( queue, timer );
693 free( timer );
694 }
695 timer = next;
696 }
697
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000698 /* remove messages */
699 for (i = 0; i < NB_MSG_KINDS; i++)
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000700 {
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000701 msg = queue->msg_list[i].first;
702 while (msg)
703 {
704 struct message *next = msg->next;
705 if (msg->win == win) remove_queue_message( queue, msg, i );
706 msg = next;
707 }
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000708 }
709}
710
Alexandre Julliard81f2a732002-03-23 20:43:52 +0000711/* post a message to a window; used by socket handling */
712void post_message( user_handle_t win, unsigned int message,
713 unsigned int wparam, unsigned int lparam )
714{
715 struct message *msg;
716 struct thread *thread = get_window_thread( win );
717
718 if (!thread) return;
719
720 if (thread->queue && (msg = mem_alloc( sizeof(*msg) )))
721 {
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;
734
735 append_message( &thread->queue->msg_list[POST_MESSAGE], msg );
736 set_queue_bits( thread->queue, QS_POSTMESSAGE );
737 }
738 release_object( thread );
739}
740
741
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000742/* get the message queue of the current thread */
743DECL_HANDLER(get_msg_queue)
744{
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000745 struct msg_queue *queue = get_current_queue();
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000746
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000747 reply->handle = 0;
748 if (queue) reply->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000749}
750
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000751
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000752/* set the current message queue wakeup mask */
753DECL_HANDLER(set_queue_mask)
754{
755 struct msg_queue *queue = get_current_queue();
756
757 if (queue)
758 {
759 queue->wake_mask = req->wake_mask;
760 queue->changed_mask = req->changed_mask;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000761 reply->wake_bits = queue->wake_bits;
762 reply->changed_bits = queue->changed_bits;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000763 if (is_signaled( queue ))
764 {
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 );
768 }
769 }
770}
771
772
773/* get the current message queue status */
774DECL_HANDLER(get_queue_status)
775{
776 struct msg_queue *queue = current->queue;
777 if (queue)
778 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000779 reply->wake_bits = queue->wake_bits;
780 reply->changed_bits = queue->changed_bits;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000781 if (req->clear) queue->changed_bits = 0;
782 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000783 else reply->wake_bits = reply->changed_bits = 0;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000784}
785
786
787/* send a message to a thread queue */
788DECL_HANDLER(send_message)
789{
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 );
794
795 if (!thread) return;
796
797 if (!(recv_queue = thread->queue))
798 {
799 set_error( STATUS_INVALID_PARAMETER );
800 release_object( thread );
801 return;
802 }
803
804 if ((msg = mem_alloc( sizeof(*msg) )))
805 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000806 msg->type = req->type;
Alexandre Julliardbc878ef2001-09-12 17:09:24 +0000807 msg->win = get_user_full_handle( req->win );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000808 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;
818
819 switch(msg->type)
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000820 {
Eric Pouech0faceb02002-01-18 19:22:55 +0000821 case MSG_OTHER_PROCESS:
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000822 msg->data_size = get_req_data_size();
823 if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size )))
Alexandre Julliarde630aa02001-07-11 17:29:01 +0000824 {
825 free( msg );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000826 break;
Alexandre Julliarde630aa02001-07-11 17:29:01 +0000827 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000828 /* 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 )))
Alexandre Julliarde630aa02001-07-11 17:29:01 +0000833 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000834 free( msg );
835 break;
Alexandre Julliarde630aa02001-07-11 17:29:01 +0000836 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000837 /* fall through */
838 case MSG_NOTIFY:
839 append_message( &recv_queue->msg_list[SEND_MESSAGE], msg );
840 set_queue_bits( recv_queue, QS_SENDMESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000841 break;
Alexandre Julliardd253c582001-08-07 19:19:08 +0000842 case MSG_POSTED:
Eric Pouech0faceb02002-01-18 19:22:55 +0000843 /* 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 )))
846 {
847 free( msg );
848 break;
849 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000850 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:
855 {
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 ))
860 {
861 free( msg );
862 break;
863 }
864 append_message( list, msg );
865 set_queue_bits( recv_queue, get_hardware_msg_bit(msg) );
866 break;
867 }
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000868 default:
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000869 set_error( STATUS_INVALID_PARAMETER );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000870 free( msg );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000871 break;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000872 }
873 }
874 release_object( thread );
875}
876
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000877/* return a message to the application, removing it from the queue if needed */
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000878static void return_message_to_app( struct msg_queue *queue, int flags,
879 struct get_message_reply *reply,
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000880 struct message *msg, enum message_kind kind )
881{
Eric Pouech0faceb02002-01-18 19:22:55 +0000882 reply->total = msg->data_size;
883 if (msg->data_size > get_reply_max_size())
884 {
885 set_error( STATUS_BUFFER_OVERFLOW );
886 return;
887 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000888 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;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000897
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000898 /* raw messages always get removed */
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000899 if ((msg->type == MSG_HARDWARE_RAW) || (flags & GET_MSG_REMOVE))
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000900 {
901 queue->last_msg = NULL;
Eric Pouech0faceb02002-01-18 19:22:55 +0000902 if (msg->data)
903 {
904 set_reply_data_ptr( msg->data, msg->data_size );
905 msg->data = NULL;
906 msg->data_size = 0;
907 }
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000908 remove_queue_message( queue, msg, kind );
909 }
910 else /* remember it as the last returned message */
911 {
Eric Pouech0faceb02002-01-18 19:22:55 +0000912 if (msg->data) set_reply_data( msg->data, msg->data_size );
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000913 queue->last_msg = msg;
914 queue->last_msg_kind = kind;
915 }
916}
917
918
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000919inline static struct message *find_matching_message( const struct message_list *list,
920 user_handle_t win,
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000921 unsigned int first, unsigned int last )
922{
923 struct message *msg;
924
925 for (msg = list->first; msg; msg = msg->next)
926 {
927 /* check against the filters */
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000928 if (msg->msg == WM_QUIT) break; /* WM_QUIT is never filtered */
Alexandre Julliarda09da0c2001-09-21 21:08:40 +0000929 if (win && msg->win && msg->win != win && !is_child_window( win, msg->win )) continue;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000930 if (msg->msg < first) continue;
931 if (msg->msg > last) continue;
932 break; /* found one */
933 }
934 return msg;
935}
936
937
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000938/* get a message from the current queue */
939DECL_HANDLER(get_message)
940{
941 struct timer *timer;
942 struct message *msg;
943 struct msg_queue *queue = get_current_queue();
Alexandre Julliardbc878ef2001-09-12 17:09:24 +0000944 user_handle_t get_win = get_user_full_handle( req->get_win );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000945
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000946 if (!queue) return;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000947
948 /* first check for sent messages */
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000949 if ((msg = queue->msg_list[SEND_MESSAGE].first))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000950 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000951 receive_message( queue, msg, reply );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000952 return;
953 }
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000954 if (req->flags & GET_MSG_SENT_ONLY) goto done; /* nothing else to check */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000955
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000956 /* 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;
960
961 /* clear changed bits so we can wait on them if we don't find a message */
962 queue->changed_bits = 0;
963
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000964 /* then check for posted messages */
Alexandre Julliardbc878ef2001-09-12 17:09:24 +0000965 if ((msg = find_matching_message( &queue->msg_list[POST_MESSAGE], get_win,
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000966 req->get_first, req->get_last )))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000967 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000968 return_message_to_app( queue, req->flags, reply, msg, POST_MESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000969 return;
970 }
971
972 /* then check for cooked hardware messages */
Alexandre Julliardbc878ef2001-09-12 17:09:24 +0000973 if ((msg = find_matching_message( &queue->msg_list[COOKED_HW_MESSAGE], get_win,
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000974 req->get_first, req->get_last )))
975 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000976 return_message_to_app( queue, req->flags, reply, msg, COOKED_HW_MESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000977 return;
978 }
979
980 /* then check for any raw hardware message */
981 if ((msg = queue->msg_list[RAW_HW_MESSAGE].first))
982 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000983 return_message_to_app( queue, req->flags, reply, msg, RAW_HW_MESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000984 return;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000985 }
986
987 /* now check for WM_PAINT */
Alexandre Julliard47f98212001-11-14 21:28:36 +0000988 if (queue->paint_count &&
989 (WM_PAINT >= req->get_first) && (WM_PAINT <= req->get_last) &&
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000990 (reply->win = find_window_to_repaint( get_win, current )))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000991 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000992 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;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001000 return;
1001 }
1002
1003 /* now check for timer */
Alexandre Julliardbc878ef2001-09-12 17:09:24 +00001004 if ((timer = find_expired_timer( queue, get_win, req->get_first,
Alexandre Julliard838d65a2001-06-19 19:16:41 +00001005 req->get_last, (req->flags & GET_MSG_REMOVE) )))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001006 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001007 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;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001016 return;
1017 }
1018
1019 done:
1020 set_error( STATUS_PENDING ); /* FIXME */
1021}
1022
1023
1024/* reply to a sent message */
1025DECL_HANDLER(reply_message)
1026{
Eric Pouech476c2b42001-05-19 17:38:21 +00001027 if (current->queue && current->queue->recv_result)
Alexandre Julliardd253c582001-08-07 19:19:08 +00001028 reply_message( current->queue, req->result, 0, req->remove,
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001029 get_req_data(), get_req_data_size() );
Eric Pouech476c2b42001-05-19 17:38:21 +00001030 else
1031 set_error( STATUS_ACCESS_DENIED );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001032}
1033
1034
1035/* retrieve the reply for the last message sent */
1036DECL_HANDLER(get_message_reply)
1037{
Alexandre Julliardd253c582001-08-07 19:19:08 +00001038 struct msg_queue *queue = current->queue;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001039
Alexandre Julliardd253c582001-08-07 19:19:08 +00001040 if (queue)
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001041 {
Alexandre Julliardd253c582001-08-07 19:19:08 +00001042 struct message_result *result = queue->send_result;
1043
1044 set_error( STATUS_PENDING );
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001045 reply->result = 0;
Alexandre Julliardd253c582001-08-07 19:19:08 +00001046
1047 if (result && (result->replied || req->cancel))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001048 {
Alexandre Julliardd253c582001-08-07 19:19:08 +00001049 if (result->replied)
1050 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001051 reply->result = result->result;
Alexandre Julliardd253c582001-08-07 19:19:08 +00001052 set_error( result->error );
1053 if (result->data)
1054 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +00001055 size_t data_len = min( result->data_size, get_reply_max_size() );
1056 set_reply_data_ptr( result->data, data_len );
Alexandre Julliardd253c582001-08-07 19:19:08 +00001057 result->data = NULL;
1058 result->data_size = 0;
1059 }
1060 }
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 );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001066 }
1067 }
Alexandre Julliardd253c582001-08-07 19:19:08 +00001068 else set_error( STATUS_ACCESS_DENIED );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001069}
1070
1071
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001072/* set a window timer */
1073DECL_HANDLER(set_win_timer)
1074{
1075 struct timer *timer;
1076 struct msg_queue *queue = get_current_queue();
Alexandre Julliardbc878ef2001-09-12 17:09:24 +00001077 user_handle_t win = get_user_full_handle( req->win );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001078
1079 if (!queue) return;
1080
1081 /* remove it if it existed already */
Alexandre Julliardbc878ef2001-09-12 17:09:24 +00001082 if (win) kill_timer( queue, win, req->msg, req->id );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001083
1084 if ((timer = set_timer( queue, req->rate )))
1085 {
Alexandre Julliardbc878ef2001-09-12 17:09:24 +00001086 timer->win = win;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001087 timer->msg = req->msg;
1088 timer->id = req->id;
1089 timer->lparam = req->lparam;
1090 }
1091}
1092
1093/* kill a window timer */
1094DECL_HANDLER(kill_win_timer)
1095{
1096 struct msg_queue *queue = current->queue;
1097
Alexandre Julliardbc878ef2001-09-12 17:09:24 +00001098 if (!queue || !kill_timer( queue, get_user_full_handle(req->win), req->msg, req->id ))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001099 set_error( STATUS_INVALID_PARAMETER );
1100}