~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/server/queue.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Server-side message queues
  3  *
  4  * Copyright (C) 2000 Alexandre Julliard
  5  *
  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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 19  */
 20 
 21 #include "config.h"
 22 #include "wine/port.h"
 23 
 24 #include <assert.h>
 25 #include <stdarg.h>
 26 #include <stdio.h>
 27 #include <stdlib.h>
 28 
 29 #include "ntstatus.h"
 30 #define WIN32_NO_STATUS
 31 #include "windef.h"
 32 #include "winbase.h"
 33 #include "wingdi.h"
 34 #include "winuser.h"
 35 #include "winternl.h"
 36 
 37 #include "handle.h"
 38 #include "file.h"
 39 #include "thread.h"
 40 #include "process.h"
 41 #include "request.h"
 42 #include "user.h"
 43 
 44 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
 45 #define WM_NCMOUSELAST  (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
 46 
 47 enum message_kind { SEND_MESSAGE, POST_MESSAGE };
 48 #define NB_MSG_KINDS (POST_MESSAGE+1)
 49 
 50 
 51 struct message_result
 52 {
 53     struct list            sender_entry;  /* entry in sender list */
 54     struct message        *msg;           /* message the result is for */
 55     struct message_result *recv_next;     /* next in receiver list */
 56     struct msg_queue      *sender;        /* sender queue */
 57     struct msg_queue      *receiver;      /* receiver queue */
 58     int                    replied;       /* has it been replied to? */
 59     unsigned int           error;         /* error code to pass back to sender */
 60     unsigned long          result;        /* reply result */
 61     struct message        *callback_msg;  /* message to queue for callback */
 62     void                  *data;          /* message reply data */
 63     unsigned int           data_size;     /* size of message reply data */
 64     struct timeout_user   *timeout;       /* result timeout */
 65 };
 66 
 67 struct message
 68 {
 69     struct list            entry;     /* entry in message list */
 70     enum message_type      type;      /* message type */
 71     user_handle_t          win;       /* window handle */
 72     unsigned int           msg;       /* message code */
 73     unsigned long          wparam;    /* parameters */
 74     unsigned long          lparam;    /* parameters */
 75     unsigned long          info;      /* extra info */
 76     int                    x;         /* x position */
 77     int                    y;         /* y position */
 78     unsigned int           time;      /* message time */
 79     void                  *data;      /* message data for sent messages */
 80     unsigned int           data_size; /* size of message data */
 81     unsigned int           unique_id; /* unique id for nested hw message waits */
 82     struct message_result *result;    /* result in sender queue */
 83 };
 84 
 85 struct timer
 86 {
 87     struct list     entry;     /* entry in timer list */
 88     timeout_t       when;      /* next expiration */
 89     unsigned int    rate;      /* timer rate in ms */
 90     user_handle_t   win;       /* window handle */
 91     unsigned int    msg;       /* message to post */
 92     unsigned long   id;        /* timer id */
 93     unsigned long   lparam;    /* lparam for message */
 94 };
 95 
 96 struct thread_input
 97 {
 98     struct object          obj;           /* object header */
 99     struct desktop        *desktop;       /* desktop that this thread input belongs to */
100     user_handle_t          focus;         /* focus window */
101     user_handle_t          capture;       /* capture window */
102     user_handle_t          active;        /* active window */
103     user_handle_t          menu_owner;    /* current menu owner window */
104     user_handle_t          move_size;     /* current moving/resizing window */
105     user_handle_t          caret;         /* caret window */
106     rectangle_t            caret_rect;    /* caret rectangle */
107     int                    caret_hide;    /* caret hide count */
108     int                    caret_state;   /* caret on/off state */
109     struct list            msg_list;      /* list of hardware messages */
110     unsigned char          keystate[256]; /* state of each key */
111 };
112 
113 struct msg_queue
114 {
115     struct object          obj;             /* object header */
116     struct fd             *fd;              /* optional file descriptor to poll */
117     unsigned int           wake_bits;       /* wakeup bits */
118     unsigned int           wake_mask;       /* wakeup mask */
119     unsigned int           changed_bits;    /* changed wakeup bits */
120     unsigned int           changed_mask;    /* changed wakeup mask */
121     int                    paint_count;     /* pending paint messages count */
122     int                    quit_message;    /* is there a pending quit message? */
123     int                    exit_code;       /* exit code of pending quit message */
124     struct list            msg_list[NB_MSG_KINDS];  /* lists of messages */
125     struct list            send_result;     /* stack of sent messages waiting for result */
126     struct list            callback_result; /* list of callback messages waiting for result */
127     struct message_result *recv_result;     /* stack of received messages waiting for result */
128     struct list            pending_timers;  /* list of pending timers */
129     struct list            expired_timers;  /* list of expired timers */
130     unsigned long          next_timer_id;   /* id for the next timer with a 0 window */
131     struct timeout_user   *timeout;         /* timeout for next timer to expire */
132     struct thread_input   *input;           /* thread input descriptor */
133     struct hook_table     *hooks;           /* hook table */
134     timeout_t              last_get_msg;    /* time of last get message call */
135 };
136 
137 static void msg_queue_dump( struct object *obj, int verbose );
138 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry );
139 static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
140 static int msg_queue_signaled( struct object *obj, struct thread *thread );
141 static int msg_queue_satisfied( struct object *obj, struct thread *thread );
142 static void msg_queue_destroy( struct object *obj );
143 static void msg_queue_poll_event( struct fd *fd, int event );
144 static void thread_input_dump( struct object *obj, int verbose );
145 static void thread_input_destroy( struct object *obj );
146 static void timer_callback( void *private );
147 
148 static const struct object_ops msg_queue_ops =
149 {
150     sizeof(struct msg_queue),  /* size */
151     msg_queue_dump,            /* dump */
152     no_get_type,               /* get_type */
153     msg_queue_add_queue,       /* add_queue */
154     msg_queue_remove_queue,    /* remove_queue */
155     msg_queue_signaled,        /* signaled */
156     msg_queue_satisfied,       /* satisfied */
157     no_signal,                 /* signal */
158     no_get_fd,                 /* get_fd */
159     no_map_access,             /* map_access */
160     default_get_sd,            /* get_sd */
161     default_set_sd,            /* set_sd */
162     no_lookup_name,            /* lookup_name */
163     no_open_file,              /* open_file */
164     no_close_handle,           /* close_handle */
165     msg_queue_destroy          /* destroy */
166 };
167 
168 static const struct fd_ops msg_queue_fd_ops =
169 {
170     NULL,                        /* get_poll_events */
171     msg_queue_poll_event,        /* poll_event */
172     NULL,                        /* flush */
173     NULL,                        /* get_fd_type */
174     NULL,                        /* ioctl */
175     NULL,                        /* queue_async */
176     NULL,                        /* reselect_async */
177     NULL                         /* cancel async */
178 };
179 
180 
181 static const struct object_ops thread_input_ops =
182 {
183     sizeof(struct thread_input),  /* size */
184     thread_input_dump,            /* dump */
185     no_get_type,                  /* get_type */
186     no_add_queue,                 /* add_queue */
187     NULL,                         /* remove_queue */
188     NULL,                         /* signaled */
189     NULL,                         /* satisfied */
190     no_signal,                    /* signal */
191     no_get_fd,                    /* get_fd */
192     no_map_access,                /* map_access */
193     default_get_sd,               /* get_sd */
194     default_set_sd,               /* set_sd */
195     no_lookup_name,               /* lookup_name */
196     no_open_file,                 /* open_file */
197     no_close_handle,              /* close_handle */
198     thread_input_destroy          /* destroy */
199 };
200 
201 /* pointer to input structure of foreground thread */
202 static struct thread_input *foreground_input;
203 static unsigned int last_input_time;
204 
205 static void free_message( struct message *msg );
206 
207 /* set the caret window in a given thread input */
208 static void set_caret_window( struct thread_input *input, user_handle_t win )
209 {
210     if (!win || win != input->caret)
211     {
212         input->caret_rect.left   = 0;
213         input->caret_rect.top    = 0;
214         input->caret_rect.right  = 0;
215         input->caret_rect.bottom = 0;
216     }
217     input->caret             = win;
218     input->caret_hide        = 1;
219     input->caret_state       = 0;
220 }
221 
222 /* create a thread input object */
223 static struct thread_input *create_thread_input( struct thread *thread )
224 {
225     struct thread_input *input;
226 
227     if ((input = alloc_object( &thread_input_ops )))
228     {
229         input->focus       = 0;
230         input->capture     = 0;
231         input->active      = 0;
232         input->menu_owner  = 0;
233         input->move_size   = 0;
234         list_init( &input->msg_list );
235         set_caret_window( input, 0 );
236         memset( input->keystate, 0, sizeof(input->keystate) );
237 
238         if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ )))
239         {
240             release_object( input );
241             return NULL;
242         }
243     }
244     return input;
245 }
246 
247 /* release the thread input data of a given thread */
248 static inline void release_thread_input( struct thread *thread )
249 {
250     struct thread_input *input = thread->queue->input;
251 
252     if (!input) return;
253     release_object( input );
254     thread->queue->input = NULL;
255 }
256 
257 /* create a message queue object */
258 static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_input *input )
259 {
260     struct msg_queue *queue;
261     int i;
262 
263     if (!input && !(input = create_thread_input( thread ))) return NULL;
264     if ((queue = alloc_object( &msg_queue_ops )))
265     {
266         queue->fd              = NULL;
267         queue->wake_bits       = 0;
268         queue->wake_mask       = 0;
269         queue->changed_bits    = 0;
270         queue->changed_mask    = 0;
271         queue->paint_count     = 0;
272         queue->quit_message    = 0;
273         queue->recv_result     = NULL;
274         queue->next_timer_id   = 0x7fff;
275         queue->timeout         = NULL;
276         queue->input           = (struct thread_input *)grab_object( input );
277         queue->hooks           = NULL;
278         queue->last_get_msg    = current_time;
279         list_init( &queue->send_result );
280         list_init( &queue->callback_result );
281         list_init( &queue->pending_timers );
282         list_init( &queue->expired_timers );
283         for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] );
284 
285         thread->queue = queue;
286         if (!thread->process->queue)
287             thread->process->queue = (struct msg_queue *)grab_object( queue );
288     }
289     release_object( input );
290     return queue;
291 }
292 
293 /* free the message queue of a thread at thread exit */
294 void free_msg_queue( struct thread *thread )
295 {
296     struct process *process = thread->process;
297 
298     remove_thread_hooks( thread );
299     if (!thread->queue) return;
300     if (process->queue == thread->queue)  /* is it the process main queue? */
301     {
302         release_object( process->queue );
303         process->queue = NULL;
304         if (process->idle_event)
305         {
306             set_event( process->idle_event );
307             release_object( process->idle_event );
308             process->idle_event = NULL;
309         }
310     }
311     release_object( thread->queue );
312     thread->queue = NULL;
313 }
314 
315 /* get the hook table for a given thread */
316 struct hook_table *get_queue_hooks( struct thread *thread )
317 {
318     if (!thread->queue) return NULL;
319     return thread->queue->hooks;
320 }
321 
322 /* set the hook table for a given thread, allocating the queue if needed */
323 void set_queue_hooks( struct thread *thread, struct hook_table *hooks )
324 {
325     struct msg_queue *queue = thread->queue;
326     if (!queue && !(queue = create_msg_queue( thread, NULL ))) return;
327     if (queue->hooks) release_object( queue->hooks );
328     queue->hooks = hooks;
329 }
330 
331 /* check the queue status */
332 static inline int is_signaled( struct msg_queue *queue )
333 {
334     return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
335 }
336 
337 /* set some queue bits */
338 static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits )
339 {
340     queue->wake_bits |= bits;
341     queue->changed_bits |= bits;
342     if (is_signaled( queue )) wake_up( &queue->obj, 0 );
343 }
344 
345 /* clear some queue bits */
346 static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits )
347 {
348     queue->wake_bits &= ~bits;
349     queue->changed_bits &= ~bits;
350 }
351 
352 /* check whether msg is a keyboard message */
353 static inline int is_keyboard_msg( struct message *msg )
354 {
355     return (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST);
356 }
357 
358 /* check if message is matched by the filter */
359 static inline int check_msg_filter( unsigned int msg, unsigned int first, unsigned int last )
360 {
361     return (msg >= first && msg <= last);
362 }
363 
364 /* check whether a message filter contains at least one potential hardware message */
365 static inline int filter_contains_hw_range( unsigned int first, unsigned int last )
366 {
367     /* hardware message ranges are (in numerical order):
368      *   WM_NCMOUSEFIRST .. WM_NCMOUSELAST
369      *   WM_KEYFIRST .. WM_KEYLAST
370      *   WM_MOUSEFIRST .. WM_MOUSELAST
371      */
372     if (last < WM_NCMOUSEFIRST) return 0;
373     if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
374     if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
375     if (first > WM_MOUSELAST) return 0;
376     return 1;
377 }
378 
379 /* get the QS_* bit corresponding to a given hardware message */
380 static inline int get_hardware_msg_bit( struct message *msg )
381 {
382     if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
383     if (is_keyboard_msg( msg )) return QS_KEY;
384     return QS_MOUSEBUTTON;
385 }
386 
387 /* get the current thread queue, creating it if needed */
388 static inline struct msg_queue *get_current_queue(void)
389 {
390     struct msg_queue *queue = current->queue;
391     if (!queue) queue = create_msg_queue( current, NULL );
392     return queue;
393 }
394 
395 /* get a (pseudo-)unique id to tag hardware messages */
396 static inline unsigned int get_unique_id(void)
397 {
398     static unsigned int id;
399     if (!++id) id = 1;  /* avoid an id of 0 */
400     return id;
401 }
402 
403 /* try to merge a message with the last in the list; return 1 if successful */
404 static int merge_message( struct thread_input *input, const struct message *msg )
405 {
406     struct message *prev;
407     struct list *ptr = list_tail( &input->msg_list );
408 
409     if (!ptr) return 0;
410     prev = LIST_ENTRY( ptr, struct message, entry );
411     if (prev->result) return 0;
412     if (prev->win && msg->win && prev->win != msg->win) return 0;
413     if (prev->msg != msg->msg) return 0;
414     if (prev->type != msg->type) return 0;
415     /* now we can merge it */
416     prev->wparam  = msg->wparam;
417     prev->lparam  = msg->lparam;
418     prev->x       = msg->x;
419     prev->y       = msg->y;
420     prev->time    = msg->time;
421     prev->info    = msg->info;
422     return 1;
423 }
424 
425 /* free a result structure */
426 static void free_result( struct message_result *result )
427 {
428     if (result->timeout) remove_timeout_user( result->timeout );
429     free( result->data );
430     if (result->callback_msg) free_message( result->callback_msg );
431     free( result );
432 }
433 
434 /* remove the result from the sender list it is on */
435 static inline void remove_result_from_sender( struct message_result *result )
436 {
437     assert( result->sender );
438 
439     list_remove( &result->sender_entry );
440     result->sender = NULL;
441     if (!result->receiver) free_result( result );
442 }
443 
444 /* store the message result in the appropriate structure */
445 static void store_message_result( struct message_result *res, unsigned long result,
446                                   unsigned int error )
447 {
448     res->result  = result;
449     res->error   = error;
450     res->replied = 1;
451     if (res->timeout)
452     {
453         remove_timeout_user( res->timeout );
454         res->timeout = NULL;
455     }
456     if (res->sender)
457     {
458         if (res->callback_msg)
459         {
460             /* queue the callback message in the sender queue */
461             struct callback_msg_data *data = res->callback_msg->data;
462             data->result = result;
463             list_add_tail( &res->sender->msg_list[SEND_MESSAGE], &res->callback_msg->entry );
464             set_queue_bits( res->sender, QS_SENDMESSAGE );
465             res->callback_msg = NULL;
466             remove_result_from_sender( res );
467         }
468         else
469         {
470             /* wake sender queue if waiting on this result */
471             if (list_head(&res->sender->send_result) == &res->sender_entry)
472                 set_queue_bits( res->sender, QS_SMRESULT );
473         }
474     }
475 
476 }
477 
478 /* free a message when deleting a queue or window */
479 static void free_message( struct message *msg )
480 {
481     struct message_result *result = msg->result;
482     if (result)
483     {
484         result->msg = NULL;
485         if (result->sender)
486         {
487             result->receiver = NULL;
488             store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ );
489         }
490         else free_result( result );
491     }
492     free( msg->data );
493     free( msg );
494 }
495 
496 /* remove (and free) a message from a message list */
497 static void remove_queue_message( struct msg_queue *queue, struct message *msg,
498                                   enum message_kind kind )
499 {
500     list_remove( &msg->entry );
501     switch(kind)
502     {
503     case SEND_MESSAGE:
504         if (list_empty( &queue->msg_list[kind] )) clear_queue_bits( queue, QS_SENDMESSAGE );
505         break;
506     case POST_MESSAGE:
507         if (list_empty( &queue->msg_list[kind] ) && !queue->quit_message)
508             clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
509         break;
510     }
511     free_message( msg );
512 }
513 
514 /* message timed out without getting a reply */
515 static void result_timeout( void *private )
516 {
517     struct message_result *result = private;
518 
519     assert( !result->replied );
520 
521     result->timeout = NULL;
522 
523     if (result->msg)  /* not received yet */
524     {
525         struct message *msg = result->msg;
526 
527         result->msg = NULL;
528         msg->result = NULL;
529         remove_queue_message( result->receiver, msg, SEND_MESSAGE );
530         result->receiver = NULL;
531         if (!result->sender)
532         {
533             free_result( result );
534             return;
535         }
536     }
537 
538     store_message_result( result, 0, STATUS_TIMEOUT );
539 }
540 
541 /* allocate and fill a message result structure */
542 static struct message_result *alloc_message_result( struct msg_queue *send_queue,
543                                                     struct msg_queue *recv_queue,
544                                                     struct message *msg, timeout_t timeout )
545 {
546     struct message_result *result = mem_alloc( sizeof(*result) );
547     if (result)
548     {
549         result->msg       = msg;
550         result->sender    = send_queue;
551         result->receiver  = recv_queue;
552         result->replied   = 0;
553         result->data      = NULL;
554         result->data_size = 0;
555         result->timeout   = NULL;
556 
557         if (msg->type == MSG_CALLBACK)
558         {
559             struct message *callback_msg = mem_alloc( sizeof(*callback_msg) );
560 
561             if (!callback_msg)
562             {
563                 free( result );
564                 return NULL;
565             }
566             callback_msg->type      = MSG_CALLBACK_RESULT;
567             callback_msg->win       = msg->win;
568             callback_msg->msg       = msg->msg;
569             callback_msg->wparam    = 0;
570             callback_msg->lparam    = 0;
571             callback_msg->time      = get_tick_count();
572             callback_msg->x         = 0;
573             callback_msg->y         = 0;
574             callback_msg->info      = 0;
575             callback_msg->result    = NULL;
576             /* steal the data from the original message */
577             callback_msg->data      = msg->data;
578             callback_msg->data_size = msg->data_size;
579             msg->data = NULL;
580             msg->data_size = 0;
581 
582             result->callback_msg = callback_msg;
583             list_add_head( &send_queue->callback_result, &result->sender_entry );
584         }
585         else
586         {
587             result->callback_msg = NULL;
588             list_add_head( &send_queue->send_result, &result->sender_entry );
589         }
590 
591         if (timeout != TIMEOUT_INFINITE)
592             result->timeout = add_timeout_user( timeout, result_timeout, result );
593     }
594     return result;
595 }
596 
597 /* receive a message, removing it from the sent queue */
598 static void receive_message( struct msg_queue *queue, struct message *msg,
599                              struct get_message_reply *reply )
600 {
601     struct message_result *result = msg->result;
602 
603     reply->total = msg->data_size;
604     if (msg->data_size > get_reply_max_size())
605     {
606         set_error( STATUS_BUFFER_OVERFLOW );
607         return;
608     }
609     reply->type   = msg->type;
610     reply->win    = msg->win;
611     reply->msg    = msg->msg;
612     reply->wparam = msg->wparam;
613     reply->lparam = msg->lparam;
614     reply->x      = msg->x;
615     reply->y      = msg->y;
616     reply->time   = msg->time;
617     reply->info   = msg->info;
618 
619     if (msg->data) set_reply_data_ptr( msg->data, msg->data_size );
620 
621     list_remove( &msg->entry );
622     /* put the result on the receiver result stack */
623     if (result)
624     {
625         result->msg = NULL;
626         result->recv_next  = queue->recv_result;
627         queue->recv_result = result;
628     }
629     free( msg );
630     if (list_empty( &queue->msg_list[SEND_MESSAGE] )) clear_queue_bits( queue, QS_SENDMESSAGE );
631 }
632 
633 /* set the result of the current received message */
634 static void reply_message( struct msg_queue *queue, unsigned long result,
635                            unsigned int error, int remove, const void *data, data_size_t len )
636 {
637     struct message_result *res = queue->recv_result;
638 
639     if (remove)
640     {
641         queue->recv_result = res->recv_next;
642         res->receiver = NULL;
643         if (!res->sender)  /* no one waiting for it */
644         {
645             free_result( res );
646             return;
647         }
648     }
649     if (!res->replied)
650     {
651         if (len && (res->data = memdup( data, len ))) res->data_size = len;
652         store_message_result( res, result, error );
653     }
654 }
655 
656 /* retrieve a posted message */
657 static int get_posted_message( struct msg_queue *queue, user_handle_t win,
658                                unsigned int first, unsigned int last, unsigned int flags,
659                                struct get_message_reply *reply )
660 {
661     struct message *msg;
662 
663     /* check against the filters */
664     LIST_FOR_EACH_ENTRY( msg, &queue->msg_list[POST_MESSAGE], struct message, entry )
665     {
666         if (win && msg->win && msg->win != win && !is_child_window( win, msg->win )) continue;
667         if (!check_msg_filter( msg->msg, first, last )) continue;
668         goto found; /* found one */
669     }
670     return 0;
671 
672     /* return it to the app */
673 found:
674     reply->total = msg->data_size;
675     if (msg->data_size > get_reply_max_size())
676     {
677         set_error( STATUS_BUFFER_OVERFLOW );
678         return 1;
679     }
680     reply->type   = msg->type;
681     reply->win    = msg->win;
682     reply->msg    = msg->msg;
683     reply->wparam = msg->wparam;
684     reply->lparam = msg->lparam;
685     reply->x      = msg->x;
686     reply->y      = msg->y;
687     reply->time   = msg->time;
688     reply->info   = msg->info;
689 
690     if (flags & PM_REMOVE)
691     {
692         if (msg->data)
693         {
694             set_reply_data_ptr( msg->data, msg->data_size );
695             msg->data = NULL;
696             msg->data_size = 0;
697         }
698         remove_queue_message( queue, msg, POST_MESSAGE );
699     }
700     else if (msg->data) set_reply_data( msg->data, msg->data_size );
701 
702     return 1;
703 }
704 
705 static int get_quit_message( struct msg_queue *queue, unsigned int flags,
706                              struct get_message_reply *reply )
707 {
708     if (queue->quit_message)
709     {
710         reply->total  = 0;
711         reply->type   = MSG_POSTED;
712         reply->win    = NULL;
713         reply->msg    = WM_QUIT;
714         reply->wparam = queue->exit_code;
715         reply->lparam = 0;
716         reply->x      = 0;
717         reply->y      = 0;
718         reply->time   = get_tick_count();
719         reply->info   = 0;
720 
721         if (flags & PM_REMOVE)
722         {
723             queue->quit_message = 0;
724             if (list_empty( &queue->msg_list[POST_MESSAGE] ))
725                 clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
726         }
727         return 1;
728     }
729     else
730         return 0;
731 }
732 
733 /* empty a message list and free all the messages */
734 static void empty_msg_list( struct list *list )
735 {
736     struct list *ptr;
737 
738     while ((ptr = list_head( list )) != NULL)
739     {
740         struct message *msg = LIST_ENTRY( ptr, struct message, entry );
741         list_remove( &msg->entry );
742         free_message( msg );
743     }
744 }
745 
746 /* cleanup all pending results when deleting a queue */
747 static void cleanup_results( struct msg_queue *queue )
748 {
749     struct list *entry;
750 
751     while ((entry = list_head( &queue->send_result )) != NULL)
752     {
753         remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
754     }
755 
756     while ((entry = list_head( &queue->callback_result )) != NULL)
757     {
758         remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
759     }
760 
761     while (queue->recv_result)
762         reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
763 }
764 
765 /* check if the thread owning the queue is hung (not checking for messages) */
766 static int is_queue_hung( struct msg_queue *queue )
767 {
768     struct wait_queue_entry *entry;
769 
770     if (current_time - queue->last_get_msg <= 5 * TICKS_PER_SEC)
771         return 0;  /* less than 5 seconds since last get message -> not hung */
772 
773     LIST_FOR_EACH_ENTRY( entry, &queue->obj.wait_queue, struct wait_queue_entry, entry )
774     {
775         if (entry->thread->queue == queue)
776             return 0;  /* thread is waiting on queue -> not hung */
777     }
778     return 1;
779 }
780 
781 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
782 {
783     struct msg_queue *queue = (struct msg_queue *)obj;
784     struct process *process = entry->thread->process;
785 
786     /* a thread can only wait on its own queue */
787     if (entry->thread->queue != queue)
788     {
789         set_error( STATUS_ACCESS_DENIED );
790         return 0;
791     }
792     /* if waiting on the main process queue, set the idle event */
793     if (process->queue == queue)
794     {
795         if (process->idle_event) set_event( process->idle_event );
796     }
797     if (queue->fd && list_empty( &obj->wait_queue ))  /* first on the queue */
798         set_fd_events( queue->fd, POLLIN );
799     add_queue( obj, entry );
800     return 1;
801 }
802 
803 static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *entry )
804 {
805     struct msg_queue *queue = (struct msg_queue *)obj;
806     struct process *process = entry->thread->process;
807 
808     remove_queue( obj, entry );
809     if (queue->fd && list_empty( &obj->wait_queue ))  /* last on the queue is gone */
810         set_fd_events( queue->fd, 0 );
811 
812     assert( entry->thread->queue == queue );
813 
814     /* if waiting on the main process queue, reset the idle event */
815     if (process->queue == queue)
816     {
817         if (process->idle_event) reset_event( process->idle_event );
818     }
819 }
820 
821 static void msg_queue_dump( struct object *obj, int verbose )
822 {
823     struct msg_queue *queue = (struct msg_queue *)obj;
824     fprintf( stderr, "Msg queue bits=%x mask=%x\n",
825              queue->wake_bits, queue->wake_mask );
826 }
827 
828 static int msg_queue_signaled( struct object *obj, struct thread *thread )
829 {
830     struct msg_queue *queue = (struct msg_queue *)obj;
831     int ret = 0;
832 
833     if (queue->fd)
834     {
835         if ((ret = check_fd_events( queue->fd, POLLIN )))
836             /* stop waiting on select() if we are signaled */
837             set_fd_events( queue->fd, 0 );
838         else if (!list_empty( &obj->wait_queue ))
839             /* restart waiting on poll() if we are no longer signaled */
840             set_fd_events( queue->fd, POLLIN );
841     }
842     return ret || is_signaled( queue );
843 }
844 
845 static int msg_queue_satisfied( struct object *obj, struct thread *thread )
846 {
847     struct msg_queue *queue = (struct msg_queue *)obj;
848     queue->wake_mask = 0;
849     queue->changed_mask = 0;
850     return 0;  /* Not abandoned */
851 }
852 
853 static void msg_queue_destroy( struct object *obj )
854 {
855     struct msg_queue *queue = (struct msg_queue *)obj;
856     struct list *ptr;
857     int i;
858 
859     cleanup_results( queue );
860     for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
861 
862     while ((ptr = list_head( &queue->pending_timers )))
863     {
864         struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
865         list_remove( &timer->entry );
866         free( timer );
867     }
868     while ((ptr = list_head( &queue->expired_timers )))
869     {
870         struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
871         list_remove( &timer->entry );
872         free( timer );
873     }
874     if (queue->timeout) remove_timeout_user( queue->timeout );
875     if (queue->input) release_object( queue->input );
876     if (queue->hooks) release_object( queue->hooks );
877     if (queue->fd) release_object( queue->fd );
878 }
879 
880 static void msg_queue_poll_event( struct fd *fd, int event )
881 {
882     struct msg_queue *queue = get_fd_user( fd );
883     assert( queue->obj.ops == &msg_queue_ops );
884 
885     if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 );
886     wake_up( &queue->obj, 0 );
887 }
888 
889 static void thread_input_dump( struct object *obj, int verbose )
890 {
891     struct thread_input *input = (struct thread_input *)obj;
892     fprintf( stderr, "Thread input focus=%p capture=%p active=%p\n",
893              input->focus, input->capture, input->active );
894 }
895 
896 static void thread_input_destroy( struct object *obj )
897 {
898     struct thread_input *input = (struct thread_input *)obj;
899 
900     if (foreground_input == input) foreground_input = NULL;
901     empty_msg_list( &input->msg_list );
902     if (input->desktop) release_object( input->desktop );
903 }
904 
905 /* fix the thread input data when a window is destroyed */
906 static inline void thread_input_cleanup_window( struct msg_queue *queue, user_handle_t window )
907 {
908     struct thread_input *input = queue->input;
909 
910     if (window == input->focus) input->focus = 0;
911     if (window == input->capture) input->capture = 0;
912     if (window == input->active) input->active = 0;
913     if (window == input->menu_owner) input->menu_owner = 0;
914     if (window == input->move_size) input->move_size = 0;
915     if (window == input->caret) set_caret_window( input, 0 );
916 }
917 
918 /* check if the specified window can be set in the input data of a given queue */
919 static int check_queue_input_window( struct msg_queue *queue, user_handle_t window )
920 {
921     struct thread *thread;
922     int ret = 0;
923 
924     if (!window) return 1;  /* we can always clear the data */
925 
926     if ((thread = get_window_thread( window )))
927     {
928         ret = (queue->input == thread->queue->input);
929         if (!ret) set_error( STATUS_ACCESS_DENIED );
930         release_object( thread );
931     }
932     else set_error( STATUS_INVALID_HANDLE );
933 
934     return ret;
935 }
936 
937 /* make sure the specified thread has a queue */
938 int init_thread_queue( struct thread *thread )
939 {
940     if (thread->queue) return 1;
941     return (create_msg_queue( thread, NULL ) != NULL);
942 }
943 
944 /* attach two thread input data structures */
945 int attach_thread_input( struct thread *thread_from, struct thread *thread_to )
946 {
947     struct desktop *desktop;
948     struct thread_input *input;
949 
950     if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0;
951     if (!(desktop = get_thread_desktop( thread_from, 0 ))) return 0;
952     input = (struct thread_input *)grab_object( thread_to->queue->input );
953     if (input->desktop != desktop)
954     {
955         set_error( STATUS_ACCESS_DENIED );
956         release_object( input );
957