blob: 4e0332b6aa67848685d99ab0a6fdf8721d99e6e9 [file] [log] [blame]
Alexandre Julliardc5e433a2000-05-30 19:48:18 +00001/*
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
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000011#include "winbase.h"
12#include "wingdi.h"
13#include "winuser.h"
14
Alexandre Julliardc5e433a2000-05-30 19:48:18 +000015#include "handle.h"
16#include "thread.h"
17#include "process.h"
18#include "request.h"
Alexandre Julliard1a66d222001-08-28 18:44:52 +000019#include "user.h"
Alexandre Julliardc5e433a2000-05-30 19:48:18 +000020
Alexandre Julliardd253c582001-08-07 19:19:08 +000021enum message_kind { SEND_MESSAGE, POST_MESSAGE, COOKED_HW_MESSAGE, RAW_HW_MESSAGE };
22#define NB_MSG_KINDS (RAW_HW_MESSAGE+1)
23
24
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000025struct message_result
26{
27 struct message_result *send_next; /* next in sender list */
28 struct message_result *recv_next; /* next in receiver list */
29 struct msg_queue *sender; /* sender queue */
30 struct msg_queue *receiver; /* receiver queue */
31 int replied; /* has it been replied to? */
32 unsigned int result; /* reply result */
33 unsigned int error; /* error code to pass back to sender */
Alexandre Julliardd253c582001-08-07 19:19:08 +000034 void *data; /* message reply data */
35 unsigned int data_size; /* size of message reply data */
36 struct timeout_user *timeout; /* result timeout */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000037};
38
39struct message
40{
41 struct message *next; /* next message in list */
42 struct message *prev; /* prev message in list */
Alexandre Julliardd253c582001-08-07 19:19:08 +000043 enum message_type type; /* message type */
Alexandre Julliard1a66d222001-08-28 18:44:52 +000044 user_handle_t win; /* window handle */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000045 unsigned int msg; /* message code */
46 unsigned int wparam; /* parameters */
47 unsigned int lparam; /* parameters */
Alexandre Julliardd253c582001-08-07 19:19:08 +000048 int x; /* x position */
49 int y; /* y position */
Alexandre Julliard838d65a2001-06-19 19:16:41 +000050 unsigned int time; /* message time */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000051 unsigned int info; /* extra info */
Alexandre Julliardd253c582001-08-07 19:19:08 +000052 void *data; /* message data for sent messages */
53 unsigned int data_size; /* size of message data */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000054 struct message_result *result; /* result in sender queue */
55};
56
57struct message_list
58{
59 struct message *first; /* head of list */
60 struct message *last; /* tail of list */
61};
62
63struct timer
64{
65 struct timer *next; /* next timer in list */
66 struct timer *prev; /* prev timer in list */
67 struct timeval when; /* next expiration */
68 unsigned int rate; /* timer rate in ms */
Alexandre Julliard1a66d222001-08-28 18:44:52 +000069 user_handle_t win; /* window handle */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000070 unsigned int msg; /* message to post */
71 unsigned int id; /* timer id */
72 unsigned int lparam; /* lparam for message */
73};
74
Alexandre Julliardc5e433a2000-05-30 19:48:18 +000075struct msg_queue
76{
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000077 struct object obj; /* object header */
78 unsigned int wake_bits; /* wakeup bits */
79 unsigned int wake_mask; /* wakeup mask */
80 unsigned int changed_bits; /* changed wakeup bits */
81 unsigned int changed_mask; /* changed wakeup mask */
Alexandre Julliard4b0343d2001-06-20 22:55:31 +000082 int paint_count; /* pending paint messages count */
Alexandre Julliard838d65a2001-06-19 19:16:41 +000083 struct message_list msg_list[NB_MSG_KINDS]; /* lists of messages */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000084 struct message_result *send_result; /* stack of sent messages waiting for result */
85 struct message_result *recv_result; /* stack of received messages waiting for result */
Alexandre Julliard9f55ae62001-06-28 04:37:22 +000086 struct message *last_msg; /* last msg returned to the app and not removed */
87 enum message_kind last_msg_kind; /* message kind of last_msg */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000088 struct timer *first_timer; /* head of timer list */
89 struct timer *last_timer; /* tail of timer list */
90 struct timer *next_timer; /* next timer to expire */
91 struct timeout_user *timeout; /* timeout for next timer to expire */
Alexandre Julliardc5e433a2000-05-30 19:48:18 +000092};
93
94static void msg_queue_dump( struct object *obj, int verbose );
95static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry );
96static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
97static int msg_queue_signaled( struct object *obj, struct thread *thread );
98static int msg_queue_satisfied( struct object *obj, struct thread *thread );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000099static void msg_queue_destroy( struct object *obj );
100static void timer_callback( void *private );
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000101
102static const struct object_ops msg_queue_ops =
103{
104 sizeof(struct msg_queue), /* size */
105 msg_queue_dump, /* dump */
106 msg_queue_add_queue, /* add_queue */
107 msg_queue_remove_queue, /* remove_queue */
108 msg_queue_signaled, /* signaled */
109 msg_queue_satisfied, /* satisfied */
110 NULL, /* get_poll_events */
111 NULL, /* poll_event */
Alexandre Julliard1ab243b2000-12-19 02:12:45 +0000112 no_get_fd, /* get_fd */
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000113 no_flush, /* flush */
114 no_get_file_info, /* get_file_info */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000115 msg_queue_destroy /* destroy */
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000116};
117
118
119static struct msg_queue *create_msg_queue( struct thread *thread )
120{
121 struct msg_queue *queue;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000122 int i;
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000123
124 if ((queue = alloc_object( &msg_queue_ops, -1 )))
125 {
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000126 queue->wake_bits = 0;
127 queue->wake_mask = 0;
128 queue->changed_bits = 0;
129 queue->changed_mask = 0;
Alexandre Julliard4b0343d2001-06-20 22:55:31 +0000130 queue->paint_count = 0;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000131 queue->send_result = NULL;
132 queue->recv_result = NULL;
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000133 queue->last_msg = NULL;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000134 queue->first_timer = NULL;
135 queue->last_timer = NULL;
136 queue->next_timer = NULL;
137 queue->timeout = NULL;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000138 for (i = 0; i < NB_MSG_KINDS; i++)
139 queue->msg_list[i].first = queue->msg_list[i].last = NULL;
140
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000141 thread->queue = queue;
142 if (!thread->process->queue)
143 thread->process->queue = (struct msg_queue *)grab_object( queue );
144 }
145 return queue;
146}
147
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000148/* check the queue status */
149inline static int is_signaled( struct msg_queue *queue )
150{
151 return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
152}
153
Alexandre Julliardd253c582001-08-07 19:19:08 +0000154/* set some queue bits */
155inline static void set_queue_bits( struct msg_queue *queue, unsigned int bits )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000156{
Alexandre Julliardd253c582001-08-07 19:19:08 +0000157 queue->wake_bits |= bits;
158 queue->changed_bits |= bits;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000159 if (is_signaled( queue )) wake_up( &queue->obj, 0 );
160}
161
Alexandre Julliardd253c582001-08-07 19:19:08 +0000162/* clear some queue bits */
163inline static void clear_queue_bits( struct msg_queue *queue, unsigned int bits )
164{
165 queue->wake_bits &= ~bits;
166 queue->changed_bits &= ~bits;
167}
168
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000169/* get the QS_* bit corresponding to a given hardware message */
170inline static int get_hardware_msg_bit( struct message *msg )
171{
172 if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
173 if (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST) return QS_KEY;
174 return QS_MOUSEBUTTON;
175}
176
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000177/* get the current thread queue, creating it if needed */
178inline struct msg_queue *get_current_queue(void)
179{
180 struct msg_queue *queue = current->queue;
181 if (!queue) queue = create_msg_queue( current );
182 return queue;
183}
184
185/* append a message to the end of a list */
186inline static void append_message( struct message_list *list, struct message *msg )
187{
188 msg->next = NULL;
189 if ((msg->prev = list->last)) msg->prev->next = msg;
190 else list->first = msg;
191 list->last = msg;
192}
193
194/* unlink a message from a list it */
195inline static void unlink_message( struct message_list *list, struct message *msg )
196{
197 if (msg->next) msg->next->prev = msg->prev;
198 else list->last = msg->prev;
199 if (msg->prev) msg->prev->next = msg->next;
200 else list->first = msg->next;
201}
202
Alexandre Julliarde630aa02001-07-11 17:29:01 +0000203/* try to merge a message with the last in the list; return 1 if successful */
204static int merge_message( struct message_list *list, const struct message *msg )
205{
206 struct message *prev = list->last;
207
208 if (!prev) return 0;
209 if (prev->result) return 0;
210 if (prev->win != msg->win) return 0;
211 if (prev->msg != msg->msg) return 0;
212 if (prev->type != msg->type) return 0;
213 /* now we can merge it */
214 prev->wparam = msg->wparam;
215 prev->lparam = msg->lparam;
216 prev->x = msg->x;
217 prev->y = msg->y;
218 prev->time = msg->time;
219 prev->info = msg->info;
220 return 1;
221}
222
Alexandre Julliardd253c582001-08-07 19:19:08 +0000223/* free a result structure */
224static void free_result( struct message_result *result )
225{
226 if (result->timeout) remove_timeout_user( result->timeout );
227 if (result->data) free( result->data );
228 free( result );
229}
230
231/* store the message result in the appropriate structure */
232static void store_message_result( struct message_result *res, unsigned int result,
233 unsigned int error )
234{
235 res->result = result;
236 res->error = error;
237 res->replied = 1;
238 if (res->timeout)
239 {
240 remove_timeout_user( res->timeout );
241 res->timeout = NULL;
242 }
243 /* wake sender queue if waiting on this result */
244 if (res->sender && res->sender->send_result == res)
245 set_queue_bits( res->sender, QS_SMRESULT );
246}
247
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000248/* free a message when deleting a queue or window */
249static void free_message( struct message *msg )
250{
251 struct message_result *result = msg->result;
252 if (result)
253 {
254 if (result->sender)
255 {
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000256 result->receiver = NULL;
Alexandre Julliardd253c582001-08-07 19:19:08 +0000257 store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000258 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000259 else free_result( result );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000260 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000261 if (msg->data) free( msg->data );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000262 free( msg );
263}
264
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000265/* remove (and free) a message from a message list */
266static void remove_queue_message( struct msg_queue *queue, struct message *msg,
267 enum message_kind kind )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000268{
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000269 int clr_bit;
270 struct message *other;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000271
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000272 if (queue->last_msg == msg) queue->last_msg = NULL;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000273 unlink_message( &queue->msg_list[kind], msg );
274 switch(kind)
275 {
276 case SEND_MESSAGE:
Alexandre Julliardd253c582001-08-07 19:19:08 +0000277 if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_SENDMESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000278 break;
279 case POST_MESSAGE:
Alexandre Julliardd253c582001-08-07 19:19:08 +0000280 if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_POSTMESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000281 break;
282 case COOKED_HW_MESSAGE:
283 case RAW_HW_MESSAGE:
284 clr_bit = get_hardware_msg_bit( msg );
285 for (other = queue->msg_list[kind].first; other; other = other->next)
286 if (get_hardware_msg_bit( other ) == clr_bit) break;
Alexandre Julliardd253c582001-08-07 19:19:08 +0000287 if (!other) clear_queue_bits( queue, clr_bit );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000288 break;
289 }
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000290 free_message( msg );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000291}
292
Alexandre Julliardd253c582001-08-07 19:19:08 +0000293/* message timed out without getting a reply */
294static void result_timeout( void *private )
295{
296 struct message_result *result = private;
297
298 assert( !result->replied );
299
300 result->timeout = NULL;
301 store_message_result( result, 0, STATUS_TIMEOUT );
302}
303
304/* allocate and fill a message result structure */
305static struct message_result *alloc_message_result( struct msg_queue *send_queue,
306 struct msg_queue *recv_queue,
307 unsigned int timeout )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000308{
309 struct message_result *result = mem_alloc( sizeof(*result) );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000310 if (result)
311 {
312 /* put the result on the sender result stack */
313 result->sender = send_queue;
314 result->receiver = recv_queue;
315 result->replied = 0;
316 result->data = NULL;
317 result->data_size = 0;
318 result->timeout = NULL;
319 result->send_next = send_queue->send_result;
320 send_queue->send_result = result;
321 if (timeout != -1)
322 {
323 struct timeval when;
324 gettimeofday( &when, 0 );
325 add_timeout( &when, timeout );
326 result->timeout = add_timeout_user( &when, result_timeout, result );
327 }
328 }
329 return result;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000330}
331
332/* receive a message, removing it from the sent queue */
333static void receive_message( struct msg_queue *queue, struct message *msg )
334{
335 struct message_result *result = msg->result;
336
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000337 unlink_message( &queue->msg_list[SEND_MESSAGE], msg );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000338 /* put the result on the receiver result stack */
Alexandre Julliardd253c582001-08-07 19:19:08 +0000339 if (result)
340 {
341 result->recv_next = queue->recv_result;
342 queue->recv_result = result;
343 }
344 if (msg->data) free( msg->data );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000345 free( msg );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000346 if (!queue->msg_list[SEND_MESSAGE].first) clear_queue_bits( queue, QS_SENDMESSAGE );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000347}
348
349/* set the result of the current received message */
350static void reply_message( struct msg_queue *queue, unsigned int result,
Alexandre Julliardd253c582001-08-07 19:19:08 +0000351 unsigned int error, int remove, void *data, size_t len )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000352{
353 struct message_result *res = queue->recv_result;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000354
355 if (remove)
356 {
357 queue->recv_result = res->recv_next;
358 res->receiver = NULL;
359 if (!res->sender) /* no one waiting for it */
360 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000361 free_result( res );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000362 return;
363 }
364 }
365 if (!res->replied)
366 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000367 if (len && (res->data = memdup( data, len ))) res->data_size = len;
368 store_message_result( res, result, error );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000369 }
370}
371
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000372/* empty a message list and free all the messages */
373static void empty_msg_list( struct message_list *list )
374{
375 struct message *msg = list->first;
376 while (msg)
377 {
378 struct message *next = msg->next;
379 free_message( msg );
380 msg = next;
381 }
382}
383
384/* cleanup all pending results when deleting a queue */
385static void cleanup_results( struct msg_queue *queue )
386{
387 struct message_result *result, *next;
388
389 result = queue->send_result;
390 while (result)
391 {
392 next = result->send_next;
393 result->sender = NULL;
Alexandre Julliardd253c582001-08-07 19:19:08 +0000394 if (!result->receiver) free_result( result );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000395 result = next;
396 }
397
Alexandre Julliardd253c582001-08-07 19:19:08 +0000398 while (queue->recv_result)
399 reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000400}
401
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000402static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
403{
404 struct msg_queue *queue = (struct msg_queue *)obj;
405 struct process *process = entry->thread->process;
406
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000407 /* a thread can only wait on its own queue */
408 if (entry->thread->queue != queue)
409 {
410 set_error( STATUS_ACCESS_DENIED );
411 return 0;
412 }
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000413 /* if waiting on the main process queue, set the idle event */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000414 if (process->queue == queue)
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000415 {
416 if (process->idle_event) set_event( process->idle_event );
417 }
418 add_queue( obj, entry );
419 return 1;
420}
421
422static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *entry )
423{
424 struct msg_queue *queue = (struct msg_queue *)obj;
425 struct process *process = entry->thread->process;
426
427 remove_queue( obj, entry );
428
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000429 assert( entry->thread->queue == queue );
430
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000431 /* if waiting on the main process queue, reset the idle event */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000432 if (process->queue == queue)
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000433 {
434 if (process->idle_event) reset_event( process->idle_event );
435 }
436}
437
438static void msg_queue_dump( struct object *obj, int verbose )
439{
440 struct msg_queue *queue = (struct msg_queue *)obj;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000441 fprintf( stderr, "Msg queue bits=%x mask=%x\n",
442 queue->wake_bits, queue->wake_mask );
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000443}
444
445static int msg_queue_signaled( struct object *obj, struct thread *thread )
446{
447 struct msg_queue *queue = (struct msg_queue *)obj;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000448 return is_signaled( queue );
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000449}
450
451static int msg_queue_satisfied( struct object *obj, struct thread *thread )
452{
453 struct msg_queue *queue = (struct msg_queue *)obj;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000454 queue->wake_mask = 0;
455 queue->changed_mask = 0;
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000456 return 0; /* Not abandoned */
457}
458
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000459static void msg_queue_destroy( struct object *obj )
460{
461 struct msg_queue *queue = (struct msg_queue *)obj;
462 struct timer *timer = queue->first_timer;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000463 int i;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000464
465 cleanup_results( queue );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000466 for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000467
468 while (timer)
469 {
470 struct timer *next = timer->next;
471 free( timer );
472 timer = next;
473 }
474 if (queue->timeout) remove_timeout_user( queue->timeout );
475}
476
477/* set the next timer to expire */
478static void set_next_timer( struct msg_queue *queue, struct timer *timer )
479{
480 if (queue->timeout)
481 {
482 remove_timeout_user( queue->timeout );
483 queue->timeout = NULL;
484 }
485 if ((queue->next_timer = timer))
486 queue->timeout = add_timeout_user( &timer->when, timer_callback, queue );
487
488 /* set/clear QS_TIMER bit */
489 if (queue->next_timer == queue->first_timer)
Alexandre Julliardd253c582001-08-07 19:19:08 +0000490 clear_queue_bits( queue, QS_TIMER );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000491 else
Alexandre Julliardd253c582001-08-07 19:19:08 +0000492 set_queue_bits( queue, QS_TIMER );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000493}
494
495/* callback for the next timer expiration */
496static void timer_callback( void *private )
497{
498 struct msg_queue *queue = private;
499
500 queue->timeout = NULL;
501 /* move on to the next timer */
502 set_next_timer( queue, queue->next_timer->next );
503}
504
505/* link a timer at its rightful place in the queue list */
506static void link_timer( struct msg_queue *queue, struct timer *timer )
507{
508 struct timer *pos = queue->next_timer;
509
510 while (pos && time_before( &pos->when, &timer->when )) pos = pos->next;
511
512 if (pos) /* insert before pos */
513 {
514 if ((timer->prev = pos->prev)) timer->prev->next = timer;
515 else queue->first_timer = timer;
516 timer->next = pos;
517 pos->prev = timer;
518 }
519 else /* insert at end */
520 {
521 timer->next = NULL;
522 timer->prev = queue->last_timer;
523 if (queue->last_timer) queue->last_timer->next = timer;
524 else queue->first_timer = timer;
525 queue->last_timer = timer;
526 }
527 /* check if we replaced the next timer */
528 if (pos == queue->next_timer) set_next_timer( queue, timer );
529}
530
531/* remove a timer from the queue timer list */
532static void unlink_timer( struct msg_queue *queue, struct timer *timer )
533{
534 if (timer->next) timer->next->prev = timer->prev;
535 else queue->last_timer = timer->prev;
536 if (timer->prev) timer->prev->next = timer->next;
537 else queue->first_timer = timer->next;
538 /* check if we removed the next timer */
539 if (queue->next_timer == timer) set_next_timer( queue, timer->next );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000540 else if (queue->next_timer == queue->first_timer) clear_queue_bits( queue, QS_TIMER );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000541}
542
543/* restart an expired timer */
544static void restart_timer( struct msg_queue *queue, struct timer *timer )
545{
546 struct timeval now;
547 unlink_timer( queue, timer );
548 gettimeofday( &now, 0 );
549 while (!time_before( &now, &timer->when )) add_timeout( &timer->when, timer->rate );
550 link_timer( queue, timer );
551}
552
553/* find an expired timer matching the filtering parameters */
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000554static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t win,
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000555 unsigned int get_first, unsigned int get_last,
556 int remove )
557{
558 struct timer *timer;
559 for (timer = queue->first_timer; (timer && timer != queue->next_timer); timer = timer->next)
560 {
561 if (win && timer->win != win) continue;
562 if (timer->msg >= get_first && timer->msg <= get_last)
563 {
564 if (remove) restart_timer( queue, timer );
565 return timer;
566 }
567 }
568 return NULL;
569}
570
571/* kill a timer */
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000572static int kill_timer( struct msg_queue *queue, user_handle_t win,
573 unsigned int msg, unsigned int id )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000574{
575 struct timer *timer;
576
577 for (timer = queue->first_timer; timer; timer = timer->next)
578 {
579 if (timer->win != win || timer->msg != msg || timer->id != id) continue;
580 unlink_timer( queue, timer );
581 free( timer );
582 return 1;
583 }
584 return 0;
585}
586
587/* add a timer */
588static struct timer *set_timer( struct msg_queue *queue, unsigned int rate )
589{
590 struct timer *timer = mem_alloc( sizeof(*timer) );
591 if (timer)
592 {
593 timer->rate = rate;
594 gettimeofday( &timer->when, 0 );
595 add_timeout( &timer->when, rate );
596 link_timer( queue, timer );
597 }
598 return timer;
599}
600
601/* remove all messages and timers belonging to a certain window */
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000602void queue_cleanup_window( struct thread *thread, user_handle_t win )
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000603{
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000604 struct msg_queue *queue = thread->queue;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000605 struct timer *timer;
606 struct message *msg;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000607 int i;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000608
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000609 if (!queue) return;
610
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000611 /* remove timers */
612 timer = queue->first_timer;
613 while (timer)
614 {
615 struct timer *next = timer->next;
616 if (timer->win == win)
617 {
618 unlink_timer( queue, timer );
619 free( timer );
620 }
621 timer = next;
622 }
623
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000624 /* remove messages */
625 for (i = 0; i < NB_MSG_KINDS; i++)
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000626 {
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000627 msg = queue->msg_list[i].first;
628 while (msg)
629 {
630 struct message *next = msg->next;
631 if (msg->win == win) remove_queue_message( queue, msg, i );
632 msg = next;
633 }
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000634 }
635}
636
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000637/* get the message queue of the current thread */
638DECL_HANDLER(get_msg_queue)
639{
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000640 struct msg_queue *queue = get_current_queue();
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000641
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000642 req->handle = 0;
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000643 if (queue) req->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
644}
645
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000646
Alexandre Julliard4b0343d2001-06-20 22:55:31 +0000647/* increment the message queue paint count */
648DECL_HANDLER(inc_queue_paint_count)
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000649{
Alexandre Julliard4b0343d2001-06-20 22:55:31 +0000650 struct msg_queue *queue;
651 struct thread *thread = get_thread_from_id( req->id );
652
653 if (!thread) return;
654
655 if ((queue = thread->queue))
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000656 {
Alexandre Julliard4b0343d2001-06-20 22:55:31 +0000657 if ((queue->paint_count += req->incr) < 0) queue->paint_count = 0;
658
659 if (queue->paint_count)
Alexandre Julliardd253c582001-08-07 19:19:08 +0000660 set_queue_bits( queue, QS_PAINT );
Alexandre Julliard4b0343d2001-06-20 22:55:31 +0000661 else
Alexandre Julliardd253c582001-08-07 19:19:08 +0000662 clear_queue_bits( queue, QS_PAINT );
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000663 }
Alexandre Julliard4b0343d2001-06-20 22:55:31 +0000664 else set_error( STATUS_INVALID_PARAMETER );
665
666 release_object( thread );
667
Alexandre Julliardc5e433a2000-05-30 19:48:18 +0000668}
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000669
670
671/* set the current message queue wakeup mask */
672DECL_HANDLER(set_queue_mask)
673{
674 struct msg_queue *queue = get_current_queue();
675
676 if (queue)
677 {
678 queue->wake_mask = req->wake_mask;
679 queue->changed_mask = req->changed_mask;
680 req->wake_bits = queue->wake_bits;
681 req->changed_bits = queue->changed_bits;
682 if (is_signaled( queue ))
683 {
684 /* if skip wait is set, do what would have been done in the subsequent wait */
685 if (req->skip_wait) msg_queue_satisfied( &queue->obj, current );
686 else wake_up( &queue->obj, 0 );
687 }
688 }
689}
690
691
692/* get the current message queue status */
693DECL_HANDLER(get_queue_status)
694{
695 struct msg_queue *queue = current->queue;
696 if (queue)
697 {
698 req->wake_bits = queue->wake_bits;
699 req->changed_bits = queue->changed_bits;
700 if (req->clear) queue->changed_bits = 0;
701 }
702 else req->wake_bits = req->changed_bits = 0;
703}
704
705
706/* send a message to a thread queue */
707DECL_HANDLER(send_message)
708{
709 struct message *msg;
710 struct msg_queue *send_queue = get_current_queue();
711 struct msg_queue *recv_queue;
712 struct thread *thread = get_thread_from_id( req->id );
713
714 if (!thread) return;
715
716 if (!(recv_queue = thread->queue))
717 {
718 set_error( STATUS_INVALID_PARAMETER );
719 release_object( thread );
720 return;
721 }
722
723 if ((msg = mem_alloc( sizeof(*msg) )))
724 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000725 msg->type = req->type;
Alexandre Julliardbc878ef2001-09-12 17:09:24 +0000726 msg->win = get_user_full_handle( req->win );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000727 msg->msg = req->msg;
728 msg->wparam = req->wparam;
729 msg->lparam = req->lparam;
730 msg->time = req->time;
731 msg->x = req->x;
732 msg->y = req->y;
733 msg->info = req->info;
734 msg->result = NULL;
735 msg->data = NULL;
736 msg->data_size = 0;
737
738 switch(msg->type)
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000739 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000740 case MSG_OTHER_PROCESS:
741 msg->data_size = get_req_data_size(req);
742 if (msg->data_size && !(msg->data = memdup( get_req_data(req), msg->data_size )))
Alexandre Julliarde630aa02001-07-11 17:29:01 +0000743 {
744 free( msg );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000745 break;
Alexandre Julliarde630aa02001-07-11 17:29:01 +0000746 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000747 /* fall through */
748 case MSG_ASCII:
749 case MSG_UNICODE:
750 case MSG_CALLBACK:
751 if (!(msg->result = alloc_message_result( send_queue, recv_queue, req->timeout )))
Alexandre Julliarde630aa02001-07-11 17:29:01 +0000752 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000753 free( msg );
754 break;
Alexandre Julliarde630aa02001-07-11 17:29:01 +0000755 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000756 /* fall through */
757 case MSG_NOTIFY:
758 append_message( &recv_queue->msg_list[SEND_MESSAGE], msg );
759 set_queue_bits( recv_queue, QS_SENDMESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000760 break;
Alexandre Julliardd253c582001-08-07 19:19:08 +0000761 case MSG_POSTED:
762 append_message( &recv_queue->msg_list[POST_MESSAGE], msg );
763 set_queue_bits( recv_queue, QS_POSTMESSAGE );
764 break;
765 case MSG_HARDWARE_RAW:
766 case MSG_HARDWARE_COOKED:
767 {
768 struct message_list *list = ((msg->type == MSG_HARDWARE_RAW) ?
769 &recv_queue->msg_list[RAW_HW_MESSAGE] :
770 &recv_queue->msg_list[COOKED_HW_MESSAGE]);
771 if (msg->msg == WM_MOUSEMOVE && merge_message( list, msg ))
772 {
773 free( msg );
774 break;
775 }
776 append_message( list, msg );
777 set_queue_bits( recv_queue, get_hardware_msg_bit(msg) );
778 break;
779 }
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000780 default:
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000781 set_error( STATUS_INVALID_PARAMETER );
Alexandre Julliardd253c582001-08-07 19:19:08 +0000782 free( msg );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000783 break;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000784 }
785 }
786 release_object( thread );
787}
788
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000789/* store a message contents into the request buffer; helper for get_message */
790inline static void put_req_message( struct get_message_request *req, const struct message *msg )
791{
Alexandre Julliardd253c582001-08-07 19:19:08 +0000792 int len = min( get_req_data_size(req), msg->data_size );
793
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000794 req->type = msg->type;
795 req->win = msg->win;
796 req->msg = msg->msg;
797 req->wparam = msg->wparam;
798 req->lparam = msg->lparam;
799 req->x = msg->x;
800 req->y = msg->y;
801 req->time = msg->time;
802 req->info = msg->info;
Alexandre Julliardd253c582001-08-07 19:19:08 +0000803 if (len) memcpy( get_req_data(req), msg->data, len );
804 set_req_data_size( req, len );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000805}
806
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000807/* return a message to the application, removing it from the queue if needed */
808static void return_message_to_app( struct msg_queue *queue, struct get_message_request *req,
809 struct message *msg, enum message_kind kind )
810{
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000811 put_req_message( req, msg );
812 /* raw messages always get removed */
Alexandre Julliardd253c582001-08-07 19:19:08 +0000813 if ((msg->type == MSG_HARDWARE_RAW) || (req->flags & GET_MSG_REMOVE))
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000814 {
815 queue->last_msg = NULL;
816 remove_queue_message( queue, msg, kind );
817 }
818 else /* remember it as the last returned message */
819 {
820 queue->last_msg = msg;
821 queue->last_msg_kind = kind;
822 }
823}
824
825
Alexandre Julliard1a66d222001-08-28 18:44:52 +0000826inline static struct message *find_matching_message( const struct message_list *list,
827 user_handle_t win,
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000828 unsigned int first, unsigned int last )
829{
830 struct message *msg;
831
832 for (msg = list->first; msg; msg = msg->next)
833 {
834 /* check against the filters */
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000835 if (msg->msg == WM_QUIT) break; /* WM_QUIT is never filtered */
Alexandre Julliarda09da0c2001-09-21 21:08:40 +0000836 if (win && msg->win && msg->win != win && !is_child_window( win, msg->win )) continue;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000837 if (msg->msg < first) continue;
838 if (msg->msg > last) continue;
839 break; /* found one */
840 }
841 return msg;
842}
843
844
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000845/* get a message from the current queue */
846DECL_HANDLER(get_message)
847{
848 struct timer *timer;
849 struct message *msg;
850 struct msg_queue *queue = get_current_queue();
Alexandre Julliardbc878ef2001-09-12 17:09:24 +0000851 user_handle_t get_win = get_user_full_handle( req->get_win );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000852
Alexandre Julliardd253c582001-08-07 19:19:08 +0000853 if (!queue)
854 {
855 set_req_data_size( req, 0 );
856 return;
857 }
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000858
859 /* first check for sent messages */
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000860 if ((msg = queue->msg_list[SEND_MESSAGE].first))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000861 {
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000862 put_req_message( req, msg );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000863 receive_message( queue, msg );
864 return;
865 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000866 set_req_data_size( req, 0 ); /* only sent messages can have data */
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000867 if (req->flags & GET_MSG_SENT_ONLY) goto done; /* nothing else to check */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000868
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000869 /* if requested, remove the last returned but not yet removed message */
870 if ((req->flags & GET_MSG_REMOVE_LAST) && queue->last_msg)
871 remove_queue_message( queue, queue->last_msg, queue->last_msg_kind );
872 queue->last_msg = NULL;
873
874 /* clear changed bits so we can wait on them if we don't find a message */
875 queue->changed_bits = 0;
876
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000877 /* then check for posted messages */
Alexandre Julliardbc878ef2001-09-12 17:09:24 +0000878 if ((msg = find_matching_message( &queue->msg_list[POST_MESSAGE], get_win,
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000879 req->get_first, req->get_last )))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000880 {
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000881 return_message_to_app( queue, req, msg, POST_MESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000882 return;
883 }
884
885 /* then check for cooked hardware messages */
Alexandre Julliardbc878ef2001-09-12 17:09:24 +0000886 if ((msg = find_matching_message( &queue->msg_list[COOKED_HW_MESSAGE], get_win,
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000887 req->get_first, req->get_last )))
888 {
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000889 return_message_to_app( queue, req, msg, COOKED_HW_MESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000890 return;
891 }
892
893 /* then check for any raw hardware message */
894 if ((msg = queue->msg_list[RAW_HW_MESSAGE].first))
895 {
Alexandre Julliard9f55ae62001-06-28 04:37:22 +0000896 return_message_to_app( queue, req, msg, RAW_HW_MESSAGE );
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000897 return;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000898 }
899
900 /* now check for WM_PAINT */
Gerard Patel63b1d172001-05-21 18:33:56 +0000901 if ((queue->wake_bits & QS_PAINT) &&
902 (WM_PAINT >= req->get_first) && (WM_PAINT <= req->get_last))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000903 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000904 req->type = MSG_POSTED;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000905 req->win = 0;
906 req->msg = WM_PAINT;
907 req->wparam = 0;
908 req->lparam = 0;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000909 req->x = 0;
910 req->y = 0;
911 req->time = 0;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000912 req->info = 0;
913 return;
914 }
915
916 /* now check for timer */
Alexandre Julliardbc878ef2001-09-12 17:09:24 +0000917 if ((timer = find_expired_timer( queue, get_win, req->get_first,
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000918 req->get_last, (req->flags & GET_MSG_REMOVE) )))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000919 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000920 req->type = MSG_POSTED;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000921 req->win = timer->win;
922 req->msg = timer->msg;
923 req->wparam = timer->id;
924 req->lparam = timer->lparam;
Alexandre Julliard838d65a2001-06-19 19:16:41 +0000925 req->x = 0;
926 req->y = 0;
927 req->time = 0;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000928 req->info = 0;
929 return;
930 }
931
932 done:
933 set_error( STATUS_PENDING ); /* FIXME */
934}
935
936
937/* reply to a sent message */
938DECL_HANDLER(reply_message)
939{
Eric Pouech476c2b42001-05-19 17:38:21 +0000940 if (current->queue && current->queue->recv_result)
Alexandre Julliardd253c582001-08-07 19:19:08 +0000941 reply_message( current->queue, req->result, 0, req->remove,
942 get_req_data(req), get_req_data_size(req) );
Eric Pouech476c2b42001-05-19 17:38:21 +0000943 else
944 set_error( STATUS_ACCESS_DENIED );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000945}
946
947
948/* retrieve the reply for the last message sent */
949DECL_HANDLER(get_message_reply)
950{
Alexandre Julliardd253c582001-08-07 19:19:08 +0000951 struct msg_queue *queue = current->queue;
952 size_t data_len = 0;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000953
Alexandre Julliardd253c582001-08-07 19:19:08 +0000954 if (queue)
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000955 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000956 struct message_result *result = queue->send_result;
957
958 set_error( STATUS_PENDING );
959 req->result = 0;
960
961 if (result && (result->replied || req->cancel))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000962 {
Alexandre Julliardd253c582001-08-07 19:19:08 +0000963 if (result->replied)
964 {
965 req->result = result->result;
966 set_error( result->error );
967 if (result->data)
968 {
969 data_len = min( result->data_size, get_req_data_size(req) );
970 memcpy( get_req_data(req), result->data, data_len );
971 free( result->data );
972 result->data = NULL;
973 result->data_size = 0;
974 }
975 }
976 queue->send_result = result->send_next;
977 result->sender = NULL;
978 if (!result->receiver) free_result( result );
979 if (!queue->send_result || !queue->send_result->replied)
980 clear_queue_bits( queue, QS_SMRESULT );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000981 }
982 }
Alexandre Julliardd253c582001-08-07 19:19:08 +0000983 else set_error( STATUS_ACCESS_DENIED );
984 set_req_data_size( req, data_len );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000985}
986
987
988/* cleanup a queue when a window is deleted */
989DECL_HANDLER(cleanup_window_queue)
990{
Alexandre Julliardbc878ef2001-09-12 17:09:24 +0000991 queue_cleanup_window( current, get_user_full_handle(req->win) );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000992}
993
994
995/* set a window timer */
996DECL_HANDLER(set_win_timer)
997{
998 struct timer *timer;
999 struct msg_queue *queue = get_current_queue();
Alexandre Julliardbc878ef2001-09-12 17:09:24 +00001000 user_handle_t win = get_user_full_handle( req->win );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001001
1002 if (!queue) return;
1003
1004 /* remove it if it existed already */
Alexandre Julliardbc878ef2001-09-12 17:09:24 +00001005 if (win) kill_timer( queue, win, req->msg, req->id );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001006
1007 if ((timer = set_timer( queue, req->rate )))
1008 {
Alexandre Julliardbc878ef2001-09-12 17:09:24 +00001009 timer->win = win;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001010 timer->msg = req->msg;
1011 timer->id = req->id;
1012 timer->lparam = req->lparam;
1013 }
1014}
1015
1016/* kill a window timer */
1017DECL_HANDLER(kill_win_timer)
1018{
1019 struct msg_queue *queue = current->queue;
1020
Alexandre Julliardbc878ef2001-09-12 17:09:24 +00001021 if (!queue || !kill_timer( queue, get_user_full_handle(req->win), req->msg, req->id ))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +00001022 set_error( STATUS_INVALID_PARAMETER );
1023}