queue.c 99.8 KB
Newer Older
1 2 3 4
/*
 * Server-side message queues
 *
 * Copyright (C) 2000 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22 23
#include "config.h"
#include "wine/port.h"

24
#include <assert.h>
25
#include <stdarg.h>
26 27
#include <stdio.h>
#include <stdlib.h>
28 29 30
#ifdef HAVE_POLL_H
# include <poll.h>
#endif
31

32 33
#include "ntstatus.h"
#define WIN32_NO_STATUS
34
#include "windef.h"
35 36 37
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
38
#include "winternl.h"
39

40
#include "handle.h"
41
#include "file.h"
42 43 44
#include "thread.h"
#include "process.h"
#include "request.h"
45
#include "user.h"
46

47
#define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
48
#define WM_NCMOUSELAST  (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
49

50 51
enum message_kind { SEND_MESSAGE, POST_MESSAGE };
#define NB_MSG_KINDS (POST_MESSAGE+1)
52 53


54 55
struct message_result
{
56
    struct list            sender_entry;  /* entry in sender list */
57
    struct message        *msg;           /* message the result is for */
58 59 60 61 62
    struct message_result *recv_next;     /* next in receiver list */
    struct msg_queue      *sender;        /* sender queue */
    struct msg_queue      *receiver;      /* receiver queue */
    int                    replied;       /* has it been replied to? */
    unsigned int           error;         /* error code to pass back to sender */
63
    lparam_t               result;        /* reply result */
64 65
    struct message        *hardware_msg;  /* hardware message if low-level hook result */
    struct desktop        *desktop;       /* desktop for hardware message */
66 67 68 69
    struct message        *callback_msg;  /* message to queue for callback */
    void                  *data;          /* message reply data */
    unsigned int           data_size;     /* size of message reply data */
    struct timeout_user   *timeout;       /* result timeout */
70 71 72 73
};

struct message
{
74
    struct list            entry;     /* entry in message list */
75
    enum message_type      type;      /* message type */
76
    user_handle_t          win;       /* window handle */
77
    unsigned int           msg;       /* message code */
78 79
    lparam_t               wparam;    /* parameters */
    lparam_t               lparam;    /* parameters */
80 81
    int                    x;         /* message position */
    int                    y;
82
    unsigned int           time;      /* message time */
83 84
    void                  *data;      /* message data for sent messages */
    unsigned int           data_size; /* size of message data */
85
    unsigned int           unique_id; /* unique id for nested hw message waits */
86 87 88 89 90
    struct message_result *result;    /* result in sender queue */
};

struct timer
{
91
    struct list     entry;     /* entry in timer list */
92
    timeout_t       when;      /* next expiration */
93
    unsigned int    rate;      /* timer rate in ms */
94
    user_handle_t   win;       /* window handle */
95
    unsigned int    msg;       /* message to post */
96 97
    lparam_t        id;        /* timer id */
    lparam_t        lparam;    /* lparam for message */
98 99
};

100 101 102
struct thread_input
{
    struct object          obj;           /* object header */
103
    struct desktop        *desktop;       /* desktop that this thread input belongs to */
104 105 106 107 108 109
    user_handle_t          focus;         /* focus window */
    user_handle_t          capture;       /* capture window */
    user_handle_t          active;        /* active window */
    user_handle_t          menu_owner;    /* current menu owner window */
    user_handle_t          move_size;     /* current moving/resizing window */
    user_handle_t          caret;         /* caret window */
110 111 112
    rectangle_t            caret_rect;    /* caret rectangle */
    int                    caret_hide;    /* caret hide count */
    int                    caret_state;   /* caret on/off state */
113 114
    user_handle_t          cursor;        /* current cursor */
    int                    cursor_count;  /* cursor show count */
115
    struct list            msg_list;      /* list of hardware messages */
116 117 118
    unsigned char          keystate[256]; /* state of each key */
};

119 120
struct msg_queue
{
121
    struct object          obj;             /* object header */
122
    struct fd             *fd;              /* optional file descriptor to poll */
123 124 125 126 127
    unsigned int           wake_bits;       /* wakeup bits */
    unsigned int           wake_mask;       /* wakeup mask */
    unsigned int           changed_bits;    /* changed wakeup bits */
    unsigned int           changed_mask;    /* changed wakeup mask */
    int                    paint_count;     /* pending paint messages count */
128
    int                    hotkey_count;    /* pending hotkey messages count */
129 130
    int                    quit_message;    /* is there a pending quit message? */
    int                    exit_code;       /* exit code of pending quit message */
131
    int                    cursor_count;    /* per-queue cursor show count */
132
    struct list            msg_list[NB_MSG_KINDS];  /* lists of messages */
133 134 135
    struct list            send_result;     /* stack of sent messages waiting for result */
    struct list            callback_result; /* list of callback messages waiting for result */
    struct message_result *recv_result;     /* stack of received messages waiting for result */
136 137
    struct list            pending_timers;  /* list of pending timers */
    struct list            expired_timers;  /* list of expired timers */
138
    lparam_t               next_timer_id;   /* id for the next timer with a 0 window */
139 140 141
    struct timeout_user   *timeout;         /* timeout for next timer to expire */
    struct thread_input   *input;           /* thread input descriptor */
    struct hook_table     *hooks;           /* hook table */
142
    timeout_t              last_get_msg;    /* time of last get message call */
143 144
};

145 146 147 148 149 150 151 152 153 154
struct hotkey
{
    struct list         entry;        /* entry in desktop hotkey list */
    struct msg_queue   *queue;        /* queue owning this hotkey */
    user_handle_t       win;          /* window handle */
    int                 id;           /* hotkey id */
    unsigned int        vkey;         /* virtual key code */
    unsigned int        flags;        /* key modifiers */
};

155 156 157
static void msg_queue_dump( struct object *obj, int verbose );
static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry );
static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
158
static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry );
159
static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry );
160
static void msg_queue_destroy( struct object *obj );
161
static void msg_queue_poll_event( struct fd *fd, int event );
162 163
static void thread_input_dump( struct object *obj, int verbose );
static void thread_input_destroy( struct object *obj );
164
static void timer_callback( void *private );
165 166 167 168 169

static const struct object_ops msg_queue_ops =
{
    sizeof(struct msg_queue),  /* size */
    msg_queue_dump,            /* dump */
170
    no_get_type,               /* get_type */
171 172 173 174
    msg_queue_add_queue,       /* add_queue */
    msg_queue_remove_queue,    /* remove_queue */
    msg_queue_signaled,        /* signaled */
    msg_queue_satisfied,       /* satisfied */
175
    no_signal,                 /* signal */
176
    no_get_fd,                 /* get_fd */
177
    no_map_access,             /* map_access */
178 179
    default_get_sd,            /* get_sd */
    default_set_sd,            /* set_sd */
180
    no_lookup_name,            /* lookup_name */
181 182
    no_link_name,              /* link_name */
    NULL,                      /* unlink_name */
183
    no_open_file,              /* open_file */
184
    no_close_handle,           /* close_handle */
185
    msg_queue_destroy          /* destroy */
186 187
};

188 189 190 191
static const struct fd_ops msg_queue_fd_ops =
{
    NULL,                        /* get_poll_events */
    msg_queue_poll_event,        /* poll_event */
192 193
    NULL,                        /* flush */
    NULL,                        /* get_fd_type */
194
    NULL,                        /* ioctl */
195
    NULL,                        /* queue_async */
196
    NULL,                        /* reselect_async */
197
    NULL                         /* cancel async */
198 199
};

200

201 202 203 204
static const struct object_ops thread_input_ops =
{
    sizeof(struct thread_input),  /* size */
    thread_input_dump,            /* dump */
205
    no_get_type,                  /* get_type */
206 207 208 209
    no_add_queue,                 /* add_queue */
    NULL,                         /* remove_queue */
    NULL,                         /* signaled */
    NULL,                         /* satisfied */
210
    no_signal,                    /* signal */
211
    no_get_fd,                    /* get_fd */
212
    no_map_access,                /* map_access */
213 214
    default_get_sd,               /* get_sd */
    default_set_sd,               /* set_sd */
215
    no_lookup_name,               /* lookup_name */
216 217
    no_link_name,                 /* link_name */
    NULL,                         /* unlink_name */
218
    no_open_file,                 /* open_file */
219
    no_close_handle,              /* close_handle */
220 221 222
    thread_input_destroy          /* destroy */
};

223
/* pointer to input structure of foreground thread */
224
static unsigned int last_input_time;
225

226
static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue );
227
static void free_message( struct message *msg );
228 229 230 231

/* set the caret window in a given thread input */
static void set_caret_window( struct thread_input *input, user_handle_t win )
{
232 233 234 235 236 237 238
    if (!win || win != input->caret)
    {
        input->caret_rect.left   = 0;
        input->caret_rect.top    = 0;
        input->caret_rect.right  = 0;
        input->caret_rect.bottom = 0;
    }
239 240 241 242 243
    input->caret             = win;
    input->caret_hide        = 1;
    input->caret_state       = 0;
}

244
/* create a thread input object */
245
static struct thread_input *create_thread_input( struct thread *thread )
246 247 248
{
    struct thread_input *input;

249
    if ((input = alloc_object( &thread_input_ops )))
250
    {
251 252 253 254 255 256 257
        input->focus        = 0;
        input->capture      = 0;
        input->active       = 0;
        input->menu_owner   = 0;
        input->move_size    = 0;
        input->cursor       = 0;
        input->cursor_count = 0;
258
        list_init( &input->msg_list );
259
        set_caret_window( input, 0 );
260
        memset( input->keystate, 0, sizeof(input->keystate) );
261 262 263 264 265 266

        if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ )))
        {
            release_object( input );
            return NULL;
        }
267 268 269 270 271 272
    }
    return input;
}

/* create a message queue object */
static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_input *input )
273
{
274
    struct thread_input *new_input = NULL;
275
    struct msg_queue *queue;
276
    int i;
277

278 279 280 281 282 283
    if (!input)
    {
        if (!(new_input = create_thread_input( thread ))) return NULL;
        input = new_input;
    }

284
    if ((queue = alloc_object( &msg_queue_ops )))
285
    {
286
        queue->fd              = NULL;
287 288 289 290
        queue->wake_bits       = 0;
        queue->wake_mask       = 0;
        queue->changed_bits    = 0;
        queue->changed_mask    = 0;
291
        queue->paint_count     = 0;
292
        queue->hotkey_count    = 0;
293
        queue->quit_message    = 0;
294
        queue->cursor_count    = 0;
295
        queue->recv_result     = NULL;
296
        queue->next_timer_id   = 0x7fff;
297
        queue->timeout         = NULL;
298
        queue->input           = (struct thread_input *)grab_object( input );
299
        queue->hooks           = NULL;
300
        queue->last_get_msg    = current_time;
301 302
        list_init( &queue->send_result );
        list_init( &queue->callback_result );
303 304
        list_init( &queue->pending_timers );
        list_init( &queue->expired_timers );
305
        for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] );
306

307 308
        thread->queue = queue;
    }
309
    if (new_input) release_object( new_input );
310 311 312
    return queue;
}

313 314 315
/* free the message queue of a thread at thread exit */
void free_msg_queue( struct thread *thread )
{
316
    remove_thread_hooks( thread );
317 318 319 320 321
    if (!thread->queue) return;
    release_object( thread->queue );
    thread->queue = NULL;
}

322 323 324
/* change the thread input data of a given thread */
static int assign_thread_input( struct thread *thread, struct thread_input *new_input )
{
325 326 327
    struct msg_queue *queue = thread->queue;

    if (!queue)
328 329 330 331
    {
        thread->queue = create_msg_queue( thread, new_input );
        return thread->queue != NULL;
    }
332 333 334 335 336 337 338
    if (queue->input)
    {
        queue->input->cursor_count -= queue->cursor_count;
        release_object( queue->input );
    }
    queue->input = (struct thread_input *)grab_object( new_input );
    new_input->cursor_count += queue->cursor_count;
339 340 341
    return 1;
}

342 343
/* allocate a hardware message and its data */
static struct message *alloc_hardware_message( lparam_t info, unsigned int time )
344 345 346 347
{
    struct hardware_msg_data *msg_data;
    struct message *msg;

348
    if (!(msg = mem_alloc( sizeof(*msg) ))) return NULL;
349 350 351
    if (!(msg_data = mem_alloc( sizeof(*msg_data) )))
    {
        free( msg );
352
        return NULL;
353
    }
354
    memset( msg, 0, sizeof(*msg) );
355
    msg->type      = MSG_HARDWARE;
356
    msg->time      = time;
357 358
    msg->data      = msg_data;
    msg->data_size = sizeof(*msg_data);
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374

    memset( msg_data, 0, sizeof(*msg_data) );
    msg_data->info   = info;
    return msg;
}

/* set the cursor position and queue the corresponding mouse message */
static void set_cursor_pos( struct desktop *desktop, int x, int y )
{
    struct message *msg;

    if (!(msg = alloc_hardware_message( 0, get_tick_count() ))) return;

    msg->msg = WM_MOUSEMOVE;
    msg->x   = x;
    msg->y   = y;
375
    queue_hardware_message( desktop, msg, 1 );
376 377
}

378 379 380 381 382 383 384 385 386 387
/* retrieve default position and time for synthesized messages */
static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsigned int *time )
{
    struct desktop *desktop = queue->input->desktop;

    *x = desktop->cursor.x;
    *y = desktop->cursor.y;
    *time = get_tick_count();
}

388
/* set the cursor clip rectangle */
389
static void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg )
390
{
391
    rectangle_t top_rect;
392
    int x, y;
393 394

    get_top_window_rectangle( desktop, &top_rect );
395 396 397 398 399 400 401 402 403 404 405 406
    if (rect)
    {
        rectangle_t new_rect = *rect;
        if (new_rect.left   < top_rect.left)   new_rect.left   = top_rect.left;
        if (new_rect.right  > top_rect.right)  new_rect.right  = top_rect.right;
        if (new_rect.top    < top_rect.top)    new_rect.top    = top_rect.top;
        if (new_rect.bottom > top_rect.bottom) new_rect.bottom = top_rect.bottom;
        if (new_rect.left > new_rect.right || new_rect.top > new_rect.bottom) new_rect = top_rect;
        desktop->cursor.clip = new_rect;
    }
    else desktop->cursor.clip = top_rect;

407
    if (desktop->cursor.clip_msg && send_clip_msg)
408
        post_desktop_message( desktop, desktop->cursor.clip_msg, rect != NULL, 0 );
409 410 411 412 413

    /* warp the mouse to be inside the clip rect */
    x = min( max( desktop->cursor.x, desktop->cursor.clip.left ), desktop->cursor.clip.right-1 );
    y = min( max( desktop->cursor.y, desktop->cursor.clip.top ), desktop->cursor.clip.bottom-1 );
    if (x != desktop->cursor.x || y != desktop->cursor.y) set_cursor_pos( desktop, x, y );
414 415
}

416 417 418 419
/* change the foreground input and reset the cursor clip rect */
static void set_foreground_input( struct desktop *desktop, struct thread_input *input )
{
    if (desktop->foreground_input == input) return;
420
    set_clip_rectangle( desktop, NULL, 1 );
421 422 423
    desktop->foreground_input = input;
}

424 425 426 427 428 429 430 431 432 433 434
/* get the hook table for a given thread */
struct hook_table *get_queue_hooks( struct thread *thread )
{
    if (!thread->queue) return NULL;
    return thread->queue->hooks;
}

/* set the hook table for a given thread, allocating the queue if needed */
void set_queue_hooks( struct thread *thread, struct hook_table *hooks )
{
    struct msg_queue *queue = thread->queue;
435
    if (!queue && !(queue = create_msg_queue( thread, NULL ))) return;
436 437 438 439
    if (queue->hooks) release_object( queue->hooks );
    queue->hooks = hooks;
}

440
/* check the queue status */
441
static inline int is_signaled( struct msg_queue *queue )
442 443 444 445
{
    return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
}

446
/* set some queue bits */
447
static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits )
448
{
449 450
    queue->wake_bits |= bits;
    queue->changed_bits |= bits;
451 452 453
    if (is_signaled( queue )) wake_up( &queue->obj, 0 );
}

454
/* clear some queue bits */
455
static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits )
456 457 458 459 460
{
    queue->wake_bits &= ~bits;
    queue->changed_bits &= ~bits;
}

461
/* check whether msg is a keyboard message */
462
static inline int is_keyboard_msg( struct message *msg )
463 464 465 466
{
    return (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST);
}

467
/* check if message is matched by the filter */
468
static inline int check_msg_filter( unsigned int msg, unsigned int first, unsigned int last )
469 470 471 472
{
    return (msg >= first && msg <= last);
}

473
/* check whether a message filter contains at least one potential hardware message */
474
static inline int filter_contains_hw_range( unsigned int first, unsigned int last )
475 476 477
{
    /* hardware message ranges are (in numerical order):
     *   WM_NCMOUSEFIRST .. WM_NCMOUSELAST
478
     *   WM_INPUT_DEVICE_CHANGE .. WM_KEYLAST
479 480 481
     *   WM_MOUSEFIRST .. WM_MOUSELAST
     */
    if (last < WM_NCMOUSEFIRST) return 0;
482
    if (first > WM_NCMOUSELAST && last < WM_INPUT_DEVICE_CHANGE) return 0;
483 484 485 486 487
    if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
    if (first > WM_MOUSELAST) return 0;
    return 1;
}

488
/* get the QS_* bit corresponding to a given hardware message */
489
static inline int get_hardware_msg_bit( struct message *msg )
490
{
491
    if (msg->msg == WM_INPUT_DEVICE_CHANGE || msg->msg == WM_INPUT) return QS_RAWINPUT;
492
    if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
493
    if (is_keyboard_msg( msg )) return QS_KEY;
494 495 496
    return QS_MOUSEBUTTON;
}

497
/* get the current thread queue, creating it if needed */
498
static inline struct msg_queue *get_current_queue(void)
499 500
{
    struct msg_queue *queue = current->queue;
501
    if (!queue) queue = create_msg_queue( current, NULL );
502 503 504
    return queue;
}

505
/* get a (pseudo-)unique id to tag hardware messages */
506
static inline unsigned int get_unique_id(void)
507 508 509 510 511 512
{
    static unsigned int id;
    if (!++id) id = 1;  /* avoid an id of 0 */
    return id;
}

513
/* try to merge a message with the last in the list; return 1 if successful */
514
static int merge_message( struct thread_input *input, const struct message *msg )
515
{
516
    struct message *prev;
517
    struct list *ptr;
518

519
    if (msg->msg != WM_MOUSEMOVE) return 0;
520 521 522 523 524 525
    for (ptr = list_tail( &input->msg_list ); ptr; ptr = list_prev( &input->msg_list, ptr ))
    {
        prev = LIST_ENTRY( ptr, struct message, entry );
        if (prev->msg != WM_INPUT) break;
    }
    if (!ptr) return 0;
526
    if (prev->result) return 0;
527
    if (prev->win && msg->win && prev->win != msg->win) return 0;
528 529 530 531 532
    if (prev->msg != msg->msg) return 0;
    if (prev->type != msg->type) return 0;
    /* now we can merge it */
    prev->wparam  = msg->wparam;
    prev->lparam  = msg->lparam;
533 534
    prev->x       = msg->x;
    prev->y       = msg->y;
535
    prev->time    = msg->time;
536 537 538 539
    if (msg->type == MSG_HARDWARE && prev->data && msg->data)
    {
        struct hardware_msg_data *prev_data = prev->data;
        struct hardware_msg_data *msg_data = msg->data;
540
        prev_data->info = msg_data->info;
541
    }
542 543
    list_remove( ptr );
    list_add_tail( &input->msg_list, ptr );
544 545 546
    return 1;
}

547 548 549 550
/* free a result structure */
static void free_result( struct message_result *result )
{
    if (result->timeout) remove_timeout_user( result->timeout );
551
    free( result->data );
552
    if (result->callback_msg) free_message( result->callback_msg );
553 554
    if (result->hardware_msg) free_message( result->hardware_msg );
    if (result->desktop) release_object( result->desktop );
555 556 557
    free( result );
}

558 559 560 561 562 563 564 565 566 567
/* remove the result from the sender list it is on */
static inline void remove_result_from_sender( struct message_result *result )
{
    assert( result->sender );

    list_remove( &result->sender_entry );
    result->sender = NULL;
    if (!result->receiver) free_result( result );
}

568
/* store the message result in the appropriate structure */
569
static void store_message_result( struct message_result *res, lparam_t result, unsigned int error )
570 571 572 573 574 575 576 577 578
{
    res->result  = result;
    res->error   = error;
    res->replied = 1;
    if (res->timeout)
    {
        remove_timeout_user( res->timeout );
        res->timeout = NULL;
    }
579 580 581 582 583 584

    if (res->hardware_msg)
    {
        if (!error && result)  /* rejected by the hook */
            free_message( res->hardware_msg );
        else
585
            queue_hardware_message( res->desktop, res->hardware_msg, 0 );
586 587 588 589

        res->hardware_msg = NULL;
    }

590 591 592 593 594
    if (res->sender)
    {
        if (res->callback_msg)
        {
            /* queue the callback message in the sender queue */
595 596
            struct callback_msg_data *data = res->callback_msg->data;
            data->result = result;
597
            list_add_tail( &res->sender->msg_list[SEND_MESSAGE], &res->callback_msg->entry );
598 599 600 601 602 603 604 605 606 607 608
            set_queue_bits( res->sender, QS_SENDMESSAGE );
            res->callback_msg = NULL;
            remove_result_from_sender( res );
        }
        else
        {
            /* wake sender queue if waiting on this result */
            if (list_head(&res->sender->send_result) == &res->sender_entry)
                set_queue_bits( res->sender, QS_SMRESULT );
        }
    }
609
    else if (!res->receiver) free_result( res );
610 611
}

612 613 614 615 616 617
/* free a message when deleting a queue or window */
static void free_message( struct message *msg )
{
    struct message_result *result = msg->result;
    if (result)
    {
618
        result->msg = NULL;
619 620
        result->receiver = NULL;
        store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ );
621
    }
622
    free( msg->data );
623 624 625
    free( msg );
}

626 627 628
/* remove (and free) a message from a message list */
static void remove_queue_message( struct msg_queue *queue, struct message *msg,
                                  enum message_kind kind )
629
{
630
    list_remove( &msg->entry );
631 632 633
    switch(kind)
    {
    case SEND_MESSAGE:
634
        if (list_empty( &queue->msg_list[kind] )) clear_queue_bits( queue, QS_SENDMESSAGE );
635 636
        break;
    case POST_MESSAGE:
637 638
        if (list_empty( &queue->msg_list[kind] ) && !queue->quit_message)
            clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
639 640
        if (msg->msg == WM_HOTKEY && --queue->hotkey_count == 0)
            clear_queue_bits( queue, QS_HOTKEY );
641 642
        break;
    }
643 644 645
    free_message( msg );
}

646 647 648 649 650 651 652 653
/* message timed out without getting a reply */
static void result_timeout( void *private )
{
    struct message_result *result = private;

    assert( !result->replied );

    result->timeout = NULL;
654 655 656 657 658 659 660 661 662 663

    if (result->msg)  /* not received yet */
    {
        struct message *msg = result->msg;

        result->msg = NULL;
        msg->result = NULL;
        remove_queue_message( result->receiver, msg, SEND_MESSAGE );
        result->receiver = NULL;
    }
664 665 666 667 668 669
    store_message_result( result, 0, STATUS_TIMEOUT );
}

/* allocate and fill a message result structure */
static struct message_result *alloc_message_result( struct msg_queue *send_queue,
                                                    struct msg_queue *recv_queue,
670
                                                    struct message *msg, timeout_t timeout )
671 672
{
    struct message_result *result = mem_alloc( sizeof(*result) );
673 674
    if (result)
    {
675 676 677 678 679 680 681 682 683 684
        result->msg          = msg;
        result->sender       = send_queue;
        result->receiver     = recv_queue;
        result->replied      = 0;
        result->data         = NULL;
        result->data_size    = 0;
        result->timeout      = NULL;
        result->hardware_msg = NULL;
        result->desktop      = NULL;
        result->callback_msg = NULL;
685 686 687 688

        if (msg->type == MSG_CALLBACK)
        {
            struct message *callback_msg = mem_alloc( sizeof(*callback_msg) );
689

690 691 692 693 694 695 696 697
            if (!callback_msg)
            {
                free( result );
                return NULL;
            }
            callback_msg->type      = MSG_CALLBACK_RESULT;
            callback_msg->win       = msg->win;
            callback_msg->msg       = msg->msg;
698
            callback_msg->wparam    = 0;
699 700 701
            callback_msg->lparam    = 0;
            callback_msg->time      = get_tick_count();
            callback_msg->result    = NULL;
702 703 704 705 706
            /* steal the data from the original message */
            callback_msg->data      = msg->data;
            callback_msg->data_size = msg->data_size;
            msg->data = NULL;
            msg->data_size = 0;
707 708 709 710

            result->callback_msg = callback_msg;
            list_add_head( &send_queue->callback_result, &result->sender_entry );
        }
711 712 713 714 715
        else if (send_queue)
        {
            list_add_head( &send_queue->send_result, &result->sender_entry );
            clear_queue_bits( send_queue, QS_SMRESULT );
        }
716

717 718
        if (timeout != TIMEOUT_INFINITE)
            result->timeout = add_timeout_user( timeout, result_timeout, result );
719 720
    }
    return result;
721 722 723
}

/* receive a message, removing it from the sent queue */
724 725
static void receive_message( struct msg_queue *queue, struct message *msg,
                             struct get_message_reply *reply )
726 727 728
{
    struct message_result *result = msg->result;

729 730 731 732 733 734 735 736 737 738 739
    reply->total = msg->data_size;
    if (msg->data_size > get_reply_max_size())
    {
        set_error( STATUS_BUFFER_OVERFLOW );
        return;
    }
    reply->type   = msg->type;
    reply->win    = msg->win;
    reply->msg    = msg->msg;
    reply->wparam = msg->wparam;
    reply->lparam = msg->lparam;
740 741
    reply->x      = msg->x;
    reply->y      = msg->y;
742 743 744 745
    reply->time   = msg->time;

    if (msg->data) set_reply_data_ptr( msg->data, msg->data_size );

746
    list_remove( &msg->entry );
747
    /* put the result on the receiver result stack */
748 749
    if (result)
    {
750
        result->msg = NULL;
751 752 753
        result->recv_next  = queue->recv_result;
        queue->recv_result = result;
    }
754
    free( msg );
755
    if (list_empty( &queue->msg_list[SEND_MESSAGE] )) clear_queue_bits( queue, QS_SENDMESSAGE );
756 757 758
}

/* set the result of the current received message */
759
static void reply_message( struct msg_queue *queue, lparam_t result,
760
                           unsigned int error, int remove, const void *data, data_size_t len )
761 762 763 764 765 766 767
{
    struct message_result *res = queue->recv_result;

    if (remove)
    {
        queue->recv_result = res->recv_next;
        res->receiver = NULL;
768
        if (!res->sender && !res->hardware_msg)  /* no one waiting for it */
769
        {
770
            free_result( res );
771 772 773 774 775
            return;
        }
    }
    if (!res->replied)
    {
776 777
        if (len && (res->data = memdup( data, len ))) res->data_size = len;
        store_message_result( res, result, error );
778 779 780
    }
}

781 782 783
static int match_window( user_handle_t win, user_handle_t msg_win )
{
    if (!win) return 1;
784
    if (win == -1 || win == 1) return !msg_win;
785 786 787 788
    if (msg_win == win) return 1;
    return is_child_window( win, msg_win );
}

789 790 791 792 793 794 795 796
/* retrieve a posted message */
static int get_posted_message( struct msg_queue *queue, user_handle_t win,
                               unsigned int first, unsigned int last, unsigned int flags,
                               struct get_message_reply *reply )
{
    struct message *msg;

    /* check against the filters */
797
    LIST_FOR_EACH_ENTRY( msg, &queue->msg_list[POST_MESSAGE], struct message, entry )
798
    {
799
        if (!match_window( win, msg->win )) continue;
800
        if (!check_msg_filter( msg->msg, first, last )) continue;
801
        goto found; /* found one */
802
    }
803
    return 0;
804 805

    /* return it to the app */
806
found:
807 808 809 810 811 812 813 814 815 816 817
    reply->total = msg->data_size;
    if (msg->data_size > get_reply_max_size())
    {
        set_error( STATUS_BUFFER_OVERFLOW );
        return 1;
    }
    reply->type   = msg->type;
    reply->win    = msg->win;
    reply->msg    = msg->msg;
    reply->wparam = msg->wparam;
    reply->lparam = msg->lparam;
818 819
    reply->x      = msg->x;
    reply->y      = msg->y;
820 821
    reply->time   = msg->time;

822
    if (flags & PM_REMOVE)
823 824 825 826 827 828 829 830 831 832 833 834 835 836
    {
        if (msg->data)
        {
            set_reply_data_ptr( msg->data, msg->data_size );
            msg->data = NULL;
            msg->data_size = 0;
        }
        remove_queue_message( queue, msg, POST_MESSAGE );
    }
    else if (msg->data) set_reply_data( msg->data, msg->data_size );

    return 1;
}

837 838 839 840 841 842 843
static int get_quit_message( struct msg_queue *queue, unsigned int flags,
                             struct get_message_reply *reply )
{
    if (queue->quit_message)
    {
        reply->total  = 0;
        reply->type   = MSG_POSTED;
844
        reply->win    = 0;
845 846 847
        reply->msg    = WM_QUIT;
        reply->wparam = queue->exit_code;
        reply->lparam = 0;
848 849

        get_message_defaults( queue, &reply->x, &reply->y, &reply->time );
850

851
        if (flags & PM_REMOVE)
852
        {
853
            queue->quit_message = 0;
854 855 856
            if (list_empty( &queue->msg_list[POST_MESSAGE] ))
                clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
        }
857 858 859 860 861 862
        return 1;
    }
    else
        return 0;
}

863
/* empty a message list and free all the messages */
864
static void empty_msg_list( struct list *list )
865
{
866 867 868
    struct list *ptr;

    while ((ptr = list_head( list )) != NULL)
869
    {
870 871
        struct message *msg = LIST_ENTRY( ptr, struct message, entry );
        list_remove( &msg->entry );
872 873 874 875 876 877 878
        free_message( msg );
    }
}

/* cleanup all pending results when deleting a queue */
static void cleanup_results( struct msg_queue *queue )
{
879 880 881 882 883 884
    struct list *entry;

    while ((entry = list_head( &queue->send_result )) != NULL)
    {
        remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
    }
885

886
    while ((entry = list_head( &queue->callback_result )) != NULL)
887
    {
888
        remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
889 890
    }

891 892
    while (queue->recv_result)
        reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
893 894
}

895 896 897 898 899
/* check if the thread owning the queue is hung (not checking for messages) */
static int is_queue_hung( struct msg_queue *queue )
{
    struct wait_queue_entry *entry;

900
    if (current_time - queue->last_get_msg <= 5 * TICKS_PER_SEC)
901 902
        return 0;  /* less than 5 seconds since last get message -> not hung */

903
    LIST_FOR_EACH_ENTRY( entry, &queue->obj.wait_queue, struct wait_queue_entry, entry )
904
    {
905
        if (get_wait_queue_thread(entry)->queue == queue)
906 907 908 909 910
            return 0;  /* thread is waiting on queue -> not hung */
    }
    return 1;
}

911 912 913
static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
{
    struct msg_queue *queue = (struct msg_queue *)obj;
914
    struct process *process = get_wait_queue_thread(entry)->process;
915

916
    /* a thread can only wait on its own queue */
917
    if (get_wait_queue_thread(entry)->queue != queue)
918 919 920 921
    {
        set_error( STATUS_ACCESS_DENIED );
        return 0;
    }
922
    if (process->idle_event && !(queue->wake_mask & QS_SMRESULT)) set_event( process->idle_event );
923

924 925
    if (queue->fd && list_empty( &obj->wait_queue ))  /* first on the queue */
        set_fd_events( queue->fd, POLLIN );
926 927 928 929 930 931 932 933 934
    add_queue( obj, entry );
    return 1;
}

static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *entry )
{
    struct msg_queue *queue = (struct msg_queue *)obj;

    remove_queue( obj, entry );
935 936
    if (queue->fd && list_empty( &obj->wait_queue ))  /* last on the queue is gone */
        set_fd_events( queue->fd, 0 );
937 938 939 940 941
}

static void msg_queue_dump( struct object *obj, int verbose )
{
    struct msg_queue *queue = (struct msg_queue *)obj;
942 943
    fprintf( stderr, "Msg queue bits=%x mask=%x\n",
             queue->wake_bits, queue->wake_mask );
944 945
}

946
static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry )
947 948
{
    struct msg_queue *queue = (struct msg_queue *)obj;
949 950 951 952 953 954 955 956 957 958 959 960
    int ret = 0;

    if (queue->fd)
    {
        if ((ret = check_fd_events( queue->fd, POLLIN )))
            /* stop waiting on select() if we are signaled */
            set_fd_events( queue->fd, 0 );
        else if (!list_empty( &obj->wait_queue ))
            /* restart waiting on poll() if we are no longer signaled */
            set_fd_events( queue->fd, POLLIN );
    }
    return ret || is_signaled( queue );
961 962
}

963
static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry )
964 965
{
    struct msg_queue *queue = (struct msg_queue *)obj;
966 967
    queue->wake_mask = 0;
    queue->changed_mask = 0;
968 969
}

970 971 972
static void msg_queue_destroy( struct object *obj )
{
    struct msg_queue *queue = (struct msg_queue *)obj;
973
    struct list *ptr;
974
    struct hotkey *hotkey, *hotkey2;
975
    int i;
976 977

    cleanup_results( queue );
978
    for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
979

980 981 982 983 984 985 986 987 988
    LIST_FOR_EACH_ENTRY_SAFE( hotkey, hotkey2, &queue->input->desktop->hotkeys, struct hotkey, entry )
    {
        if (hotkey->queue == queue)
        {
            list_remove( &hotkey->entry );
            free( hotkey );
        }
    }

989
    while ((ptr = list_head( &queue->pending_timers )))
990
    {
991 992 993 994 995 996 997 998
        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
        list_remove( &timer->entry );
        free( timer );
    }
    while ((ptr = list_head( &queue->expired_timers )))
    {
        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
        list_remove( &timer->entry );
999 1000 1001
        free( timer );
    }
    if (queue->timeout) remove_timeout_user( queue->timeout );
1002 1003
    queue->input->cursor_count -= queue->cursor_count;
    release_object( queue->input );
1004
    if (queue->hooks) release_object( queue->hooks );
1005 1006 1007 1008 1009 1010 1011 1012 1013
    if (queue->fd) release_object( queue->fd );
}

static void msg_queue_poll_event( struct fd *fd, int event )
{
    struct msg_queue *queue = get_fd_user( fd );
    assert( queue->obj.ops == &msg_queue_ops );

    if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 );
1014
    else set_fd_events( queue->fd, 0 );
1015
    wake_up( &queue->obj, 0 );
1016 1017 1018 1019 1020
}

static void thread_input_dump( struct object *obj, int verbose )
{
    struct thread_input *input = (struct thread_input *)obj;
1021
    fprintf( stderr, "Thread input focus=%08x capture=%08x active=%08x\n",
1022 1023 1024 1025 1026 1027 1028
             input->focus, input->capture, input->active );
}

static void thread_input_destroy( struct object *obj )
{
    struct thread_input *input = (struct thread_input *)obj;

1029
    empty_msg_list( &input->msg_list );
1030 1031
    if (input->desktop)
    {
1032
        if (input->desktop->foreground_input == input) set_foreground_input( input->desktop, NULL );
1033 1034
        release_object( input->desktop );
    }
1035 1036 1037
}

/* fix the thread input data when a window is destroyed */
1038
static inline void thread_input_cleanup_window( struct msg_queue *queue, user_handle_t window )
1039 1040 1041 1042 1043 1044 1045 1046
{
    struct thread_input *input = queue->input;

    if (window == input->focus) input->focus = 0;
    if (window == input->capture) input->capture = 0;
    if (window == input->active) input->active = 0;
    if (window == input->menu_owner) input->menu_owner = 0;
    if (window == input->move_size) input->move_size = 0;
1047
    if (window == input->caret) set_caret_window( input, 0 );
1048 1049
}

1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
/* check if the specified window can be set in the input data of a given queue */
static int check_queue_input_window( struct msg_queue *queue, user_handle_t window )
{
    struct thread *thread;
    int ret = 0;

    if (!window) return 1;  /* we can always clear the data */

    if ((thread = get_window_thread( window )))
    {
        ret = (queue->input == thread->queue->input);
        if (!ret) set_error( STATUS_ACCESS_DENIED );
        release_object( thread );
    }
    else set_error( STATUS_INVALID_HANDLE );

    return ret;
}

1069 1070 1071 1072 1073 1074 1075
/* make sure the specified thread has a queue */
int init_thread_queue( struct thread *thread )
{
    if (thread->queue) return 1;
    return (create_msg_queue( thread, NULL ) != NULL);
}

1076 1077 1078
/* attach two thread input data structures */
int attach_thread_input( struct thread *thread_from, struct thread *thread_to )
{
1079
    struct desktop *desktop;
1080
    struct thread_input *input;
1081
    int ret;
1082 1083

    if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0;
1084
    if (!(desktop = get_thread_desktop( thread_from, 0 ))) return 0;
1085
    input = (struct thread_input *)grab_object( thread_to->queue->input );
1086 1087 1088 1089 1090 1091 1092 1093
    if (input->desktop != desktop)
    {
        set_error( STATUS_ACCESS_DENIED );
        release_object( input );
        release_object( desktop );
        return 0;
    }
    release_object( desktop );
1094

1095 1096 1097 1098 1099 1100
    if (thread_from->queue)
    {
        if (!input->focus) input->focus = thread_from->queue->input->focus;
        if (!input->active) input->active = thread_from->queue->input->active;
    }

1101 1102 1103 1104
    ret = assign_thread_input( thread_from, input );
    if (ret) memset( input->keystate, 0, sizeof(input->keystate) );
    release_object( input );
    return ret;
1105 1106
}

1107
/* detach two thread input data structures */
1108
void detach_thread_input( struct thread *thread_from )
1109
{
1110 1111
    struct thread *thread;
    struct thread_input *input, *old_input = thread_from->queue->input;
1112

1113
    if ((input = create_thread_input( thread_from )))
1114
    {
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
        if (old_input->focus && (thread = get_window_thread( old_input->focus )))
        {
            if (thread == thread_from)
            {
                input->focus = old_input->focus;
                old_input->focus = 0;
            }
            release_object( thread );
        }
        if (old_input->active && (thread = get_window_thread( old_input->active )))
        {
            if (thread == thread_from)
            {
                input->active = old_input->active;
                old_input->active = 0;
            }
            release_object( thread );
        }
1133 1134
        assign_thread_input( thread_from, input );
        release_object( input );
1135 1136 1137 1138
    }
}


1139
/* set the next timer to expire */
1140
static void set_next_timer( struct msg_queue *queue )
1141
{
1142 1143
    struct list *ptr;

1144 1145 1146 1147 1148
    if (queue->timeout)
    {
        remove_timeout_user( queue->timeout );
        queue->timeout = NULL;
    }
1149 1150 1151
    if ((ptr = list_head( &queue->pending_timers )))
    {
        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
1152
        queue->timeout = add_timeout_user( timer->when, timer_callback, queue );
1153
    }
1154
    /* set/clear QS_TIMER bit */
1155
    if (list_empty( &queue->expired_timers ))
1156
        clear_queue_bits( queue, QS_TIMER );
1157
    else
1158
        set_queue_bits( queue, QS_TIMER );
1159 1160
}

1161 1162
/* find a timer from its window and id */
static struct timer *find_timer( struct msg_queue *queue, user_handle_t win,
1163
                                 unsigned int msg, lparam_t id )
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
{
    struct list *ptr;

    /* we need to search both lists */

    LIST_FOR_EACH( ptr, &queue->pending_timers )
    {
        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
        if (timer->win == win && timer->msg == msg && timer->id == id) return timer;
    }
    LIST_FOR_EACH( ptr, &queue->expired_timers )
    {
        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
        if (timer->win == win && timer->msg == msg && timer->id == id) return timer;
    }
    return NULL;
}

1182 1183 1184 1185
/* callback for the next timer expiration */
static void timer_callback( void *private )
{
    struct msg_queue *queue = private;
1186
    struct list *ptr;
1187 1188 1189

    queue->timeout = NULL;
    /* move on to the next timer */
1190 1191 1192 1193
    ptr = list_head( &queue->pending_timers );
    list_remove( ptr );
    list_add_tail( &queue->expired_timers, ptr );
    set_next_timer( queue );
1194 1195 1196 1197 1198
}

/* link a timer at its rightful place in the queue list */
static void link_timer( struct msg_queue *queue, struct timer *timer )
{
1199
    struct list *ptr;
1200

1201
    for (ptr = queue->pending_timers.next; ptr != &queue->pending_timers; ptr = ptr->next)
1202
    {
1203
        struct timer *t = LIST_ENTRY( ptr, struct timer, entry );
1204
        if (t->when >= timer->when) break;
1205
    }
1206
    list_add_before( ptr, &timer->entry );
1207 1208
}

1209 1210
/* remove a timer from the queue timer list and free it */
static void free_timer( struct msg_queue *queue, struct timer *timer )
1211
{
1212 1213 1214
    list_remove( &timer->entry );
    free( timer );
    set_next_timer( queue );
1215 1216 1217 1218 1219
}

/* restart an expired timer */
static void restart_timer( struct msg_queue *queue, struct timer *timer )
{
1220
    list_remove( &timer->entry );
1221
    while (timer->when <= current_time) timer->when += (timeout_t)timer->rate * 10000;
1222
    link_timer( queue, timer );
1223
    set_next_timer( queue );
1224 1225 1226
}

/* find an expired timer matching the filtering parameters */
1227
static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t win,
1228 1229 1230
                                         unsigned int get_first, unsigned int get_last,
                                         int remove )
{
1231 1232 1233
    struct list *ptr;

    LIST_FOR_EACH( ptr, &queue->expired_timers )
1234
    {
1235
        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
1236
        if (win && timer->win != win) continue;
1237
        if (check_msg_filter( timer->msg, get_first, get_last ))
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
        {
            if (remove) restart_timer( queue, timer );
            return timer;
        }
    }
    return NULL;
}

/* add a timer */
static struct timer *set_timer( struct msg_queue *queue, unsigned int rate )
{
    struct timer *timer = mem_alloc( sizeof(*timer) );
    if (timer)
    {
1252
        timer->rate = max( rate, 1 );
1253
        timer->when = current_time + (timeout_t)timer->rate * 10000;
1254
        link_timer( queue, timer );
1255 1256
        /* check if we replaced the next timer */
        if (list_head( &queue->pending_timers ) == &timer->entry) set_next_timer( queue );
1257 1258 1259 1260
    }
    return timer;
}

1261
/* change the input key state for a given key */
1262
static void set_input_key_state( unsigned char *keystate, unsigned char key, int down )
1263 1264 1265
{
    if (down)
    {
1266
        if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1267
        keystate[key] |= down;
1268
    }
1269
    else keystate[key] &= ~0x80;
1270 1271 1272
}

/* update the input key state for a keyboard message */
1273 1274
static void update_input_key_state( struct desktop *desktop, unsigned char *keystate,
                                    const struct message *msg )
1275 1276
{
    unsigned char key;
1277
    int down = 0;
1278 1279 1280 1281

    switch (msg->msg)
    {
    case WM_LBUTTONDOWN:
1282
        down = (keystate == desktop->keystate) ? 0xc0 : 0x80;
1283 1284
        /* fall through */
    case WM_LBUTTONUP:
1285
        set_input_key_state( keystate, VK_LBUTTON, down );
1286 1287
        break;
    case WM_MBUTTONDOWN:
1288
        down = (keystate == desktop->keystate) ? 0xc0 : 0x80;
1289 1290
        /* fall through */
    case WM_MBUTTONUP:
1291
        set_input_key_state( keystate, VK_MBUTTON, down );
1292 1293
        break;
    case WM_RBUTTONDOWN:
1294
        down = (keystate == desktop->keystate) ? 0xc0 : 0x80;
1295 1296
        /* fall through */
    case WM_RBUTTONUP:
1297
        set_input_key_state( keystate, VK_RBUTTON, down );
1298
        break;
1299
    case WM_XBUTTONDOWN:
1300
        down = (keystate == desktop->keystate) ? 0xc0 : 0x80;
1301 1302
        /* fall through */
    case WM_XBUTTONUP:
1303 1304
        if (msg->wparam >> 16 == XBUTTON1) set_input_key_state( keystate, VK_XBUTTON1, down );
        else if (msg->wparam >> 16 == XBUTTON2) set_input_key_state( keystate, VK_XBUTTON2, down );
1305
        break;
1306 1307
    case WM_KEYDOWN:
    case WM_SYSKEYDOWN:
1308
        down = (keystate == desktop->keystate) ? 0xc0 : 0x80;
1309 1310 1311 1312
        /* fall through */
    case WM_KEYUP:
    case WM_SYSKEYUP:
        key = (unsigned char)msg->wparam;
1313
        set_input_key_state( keystate, key, down );
1314 1315
        switch(key)
        {
1316 1317
        case VK_LCONTROL:
        case VK_RCONTROL:
1318 1319
            down = (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80;
            set_input_key_state( keystate, VK_CONTROL, down );
1320 1321 1322
            break;
        case VK_LMENU:
        case VK_RMENU:
1323 1324
            down = (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80;
            set_input_key_state( keystate, VK_MENU, down );
1325 1326 1327
            break;
        case VK_LSHIFT:
        case VK_RSHIFT:
1328 1329
            down = (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80;
            set_input_key_state( keystate, VK_SHIFT, down );
1330
            break;
1331 1332 1333 1334 1335
        }
        break;
    }
}

1336
/* release the hardware message currently being processed by the given thread */
1337
static void release_hardware_message( struct msg_queue *queue, unsigned int hw_id,
1338
                                      int remove )
1339
{
1340 1341
    struct thread_input *input = queue->input;
    struct message *msg;
1342

1343 1344 1345 1346 1347
    LIST_FOR_EACH_ENTRY( msg, &input->msg_list, struct message, entry )
    {
        if (msg->unique_id == hw_id) break;
    }
    if (&msg->entry == &input->msg_list) return;  /* not found */
1348 1349

    /* clear the queue bit for that message */
1350
    if (remove)
1351 1352 1353 1354
    {
        struct message *other;
        int clr_bit;

1355
        clr_bit = get_hardware_msg_bit( msg );
1356 1357
        LIST_FOR_EACH_ENTRY( other, &input->msg_list, struct message, entry )
        {
1358
            if (other != msg && get_hardware_msg_bit( other ) == clr_bit)
1359 1360 1361 1362 1363
            {
                clr_bit = 0;
                break;
            }
        }
1364
        if (clr_bit) clear_queue_bits( queue, clr_bit );
1365

1366
        update_input_key_state( input->desktop, input->keystate, msg );
1367 1368
        list_remove( &msg->entry );
        free_message( msg );
1369 1370 1371
    }
}

1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
static int queue_hotkey_message( struct desktop *desktop, struct message *msg )
{
    struct hotkey *hotkey;
    unsigned int modifiers = 0;

    if (msg->msg != WM_KEYDOWN) return 0;

    if (desktop->keystate[VK_MENU] & 0x80) modifiers |= MOD_ALT;
    if (desktop->keystate[VK_CONTROL] & 0x80) modifiers |= MOD_CONTROL;
    if (desktop->keystate[VK_SHIFT] & 0x80) modifiers |= MOD_SHIFT;
    if ((desktop->keystate[VK_LWIN] & 0x80) || (desktop->keystate[VK_RWIN] & 0x80)) modifiers |= MOD_WIN;

    LIST_FOR_EACH_ENTRY( hotkey, &desktop->hotkeys, struct hotkey, entry )
    {
        if (hotkey->vkey != msg->wparam) continue;
        if ((hotkey->flags & (MOD_ALT|MOD_CONTROL|MOD_SHIFT|MOD_WIN)) == modifiers) goto found;
    }

    return 0;

found:
    msg->type      = MSG_POSTED;
    msg->win       = hotkey->win;
    msg->msg       = WM_HOTKEY;
    msg->wparam    = hotkey->id;
    msg->lparam    = ((hotkey->vkey & 0xffff) << 16) | modifiers;

    free( msg->data );
    msg->data      = NULL;
    msg->data_size = 0;

    list_add_tail( &hotkey->queue->msg_list[POST_MESSAGE], &msg->entry );
1404 1405
    set_queue_bits( hotkey->queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE|QS_HOTKEY );
    hotkey->queue->hotkey_count++;
1406 1407 1408
    return 1;
}

1409
/* find the window that should receive a given hardware message */
1410
static user_handle_t find_hardware_message_window( struct desktop *desktop, struct thread_input *input,
1411 1412
                                                   struct message *msg, unsigned int *msg_code,
                                                   struct thread **thread )
1413 1414 1415
{
    user_handle_t win = 0;

1416
    *thread = NULL;
1417
    *msg_code = msg->msg;
1418 1419 1420 1421 1422
    if (msg->msg == WM_INPUT)
    {
        if (!(win = msg->win) && input) win = input->focus;
    }
    else if (is_keyboard_msg( msg ))
1423
    {
1424 1425 1426 1427 1428
        if (input && !(win = input->focus))
        {
            win = input->active;
            if (*msg_code < WM_SYSKEYDOWN) *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN;
        }
1429
    }
1430
    else if (!input || !(win = input->capture)) /* mouse message */
1431
    {
1432
        if (is_window_visible( msg->win ) && !is_window_transparent( msg->win )) win = msg->win;
1433
        else win = shallow_window_from_point( desktop, msg->x, msg->y );
1434

1435
        *thread = window_thread_from_point( win, msg->x, msg->y );
1436
    }
1437 1438 1439

    if (!*thread)
        *thread = get_window_thread( win );
1440 1441 1442
    return win;
}

1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476
static struct rawinput_device_entry *find_rawinput_device( unsigned short usage_page, unsigned short usage )
{
    struct rawinput_device_entry *e;

    LIST_FOR_EACH_ENTRY( e, &current->process->rawinput_devices, struct rawinput_device_entry, entry )
    {
        if (e->device.usage_page != usage_page || e->device.usage != usage) continue;
        return e;
    }

    return NULL;
}

static void update_rawinput_device(const struct rawinput_device *device)
{
    struct rawinput_device_entry *e;

    if (!(e = find_rawinput_device( device->usage_page, device->usage )))
    {
        if (!(e = mem_alloc( sizeof(*e) ))) return;
        list_add_tail( &current->process->rawinput_devices, &e->entry );
    }

    if (device->flags & RIDEV_REMOVE)
    {
        list_remove( &e->entry );
        free( e );
        return;
    }

    e->device = *device;
    e->device.target = get_user_full_handle( e->device.target );
}

1477
/* queue a hardware message into a given thread input */
1478
static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue )
1479 1480
{
    user_handle_t win;
1481
    struct thread *thread;
1482
    struct thread_input *input;
1483
    unsigned int msg_code;
1484

1485
    update_input_key_state( desktop, desktop->keystate, msg );
1486
    last_input_time = get_tick_count();
1487
    if (msg->msg != WM_MOUSEMOVE) always_queue = 1;
1488

1489 1490
    if (is_keyboard_msg( msg ))
    {
1491
        if (queue_hotkey_message( desktop, msg )) return;
1492 1493 1494 1495
        if (desktop->keystate[VK_MENU] & 0x80) msg->lparam |= KF_ALTDOWN << 16;
        if (msg->wparam == VK_SHIFT || msg->wparam == VK_LSHIFT || msg->wparam == VK_RSHIFT)
            msg->lparam &= ~(KF_EXTENDED << 16);
    }
1496
    else if (msg->msg != WM_INPUT)
1497
    {
1498 1499
        if (msg->msg == WM_MOUSEMOVE)
        {
1500 1501
            int x = min( max( msg->x, desktop->cursor.clip.left ), desktop->cursor.clip.right-1 );
            int y = min( max( msg->y, desktop->cursor.clip.top ), desktop->cursor.clip.bottom-1 );
1502 1503 1504
            if (desktop->cursor.x != x || desktop->cursor.y != y) always_queue = 1;
            desktop->cursor.x = x;
            desktop->cursor.y = y;
1505 1506
            desktop->cursor.last_change = get_tick_count();
        }
1507 1508 1509 1510 1511 1512 1513 1514
        if (desktop->keystate[VK_LBUTTON] & 0x80)  msg->wparam |= MK_LBUTTON;
        if (desktop->keystate[VK_MBUTTON] & 0x80)  msg->wparam |= MK_MBUTTON;
        if (desktop->keystate[VK_RBUTTON] & 0x80)  msg->wparam |= MK_RBUTTON;
        if (desktop->keystate[VK_SHIFT] & 0x80)    msg->wparam |= MK_SHIFT;
        if (desktop->keystate[VK_CONTROL] & 0x80)  msg->wparam |= MK_CONTROL;
        if (desktop->keystate[VK_XBUTTON1] & 0x80) msg->wparam |= MK_XBUTTON1;
        if (desktop->keystate[VK_XBUTTON2] & 0x80) msg->wparam |= MK_XBUTTON2;
    }
1515 1516
    msg->x = desktop->cursor.x;
    msg->y = desktop->cursor.y;
1517

1518 1519 1520 1521 1522 1523 1524
    if (msg->win && (thread = get_window_thread( msg->win )))
    {
        input = thread->queue->input;
        release_object( thread );
    }
    else input = desktop->foreground_input;

1525 1526
    win = find_hardware_message_window( desktop, input, msg, &msg_code, &thread );
    if (!win || !thread)
1527
    {
1528
        if (input) update_input_key_state( input->desktop, input->keystate, msg );
1529
        free_message( msg );
1530 1531
        return;
    }
1532
    input = thread->queue->input;
1533

1534 1535 1536 1537
    if (win != desktop->cursor.win) always_queue = 1;
    desktop->cursor.win = win;

    if (!always_queue || merge_message( input, msg )) free_message( msg );
1538 1539
    else
    {
1540
        msg->unique_id = 0;  /* will be set once we return it to the app */
1541
        list_add_tail( &input->msg_list, &msg->entry );
1542 1543
        set_queue_bits( thread->queue, get_hardware_msg_bit(msg) );
    }
1544
    release_object( thread );
1545 1546
}

1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558
/* send the low-level hook message for a given hardware message */
static int send_hook_ll_message( struct desktop *desktop, struct message *hardware_msg,
                                 const hw_input_t *input, struct msg_queue *sender )
{
    struct thread *hook_thread;
    struct msg_queue *queue;
    struct message *msg;
    timeout_t timeout = 2000 * -10000;  /* FIXME: load from registry */
    int id = (input->type == INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL;

    if (!(hook_thread = get_first_global_hook( id ))) return 0;
    if (!(queue = hook_thread->queue)) return 0;
1559
    if (is_queue_hung( queue )) return 0;
1560 1561 1562 1563 1564 1565 1566

    if (!(msg = mem_alloc( sizeof(*msg) ))) return 0;

    msg->type      = MSG_HOOK_LL;
    msg->win       = 0;
    msg->msg       = id;
    msg->wparam    = hardware_msg->msg;
1567 1568
    msg->x         = hardware_msg->x;
    msg->y         = hardware_msg->y;
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578
    msg->time      = hardware_msg->time;
    msg->data_size = hardware_msg->data_size;
    msg->result    = NULL;

    if (input->type == INPUT_KEYBOARD)
    {
        unsigned short vkey = input->kbd.vkey;
        if (input->kbd.flags & KEYEVENTF_UNICODE) vkey = VK_PACKET;
        msg->lparam = (input->kbd.scan << 16) | vkey;
    }
1579
    else msg->lparam = input->mouse.data << 16;
1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593

    if (!(msg->data = memdup( hardware_msg->data, hardware_msg->data_size )) ||
        !(msg->result = alloc_message_result( sender, queue, msg, timeout )))
    {
        free_message( msg );
        return 0;
    }
    msg->result->hardware_msg = hardware_msg;
    msg->result->desktop = (struct desktop *)grab_object( desktop );
    list_add_tail( &queue->msg_list[SEND_MESSAGE], &msg->entry );
    set_queue_bits( queue, QS_SENDMESSAGE );
    return 1;
}

1594
/* queue a hardware message for a mouse event */
1595 1596
static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
                                unsigned int hook_flags, struct msg_queue *sender )
1597
{
1598
    const struct rawinput_device *device;
1599 1600
    struct hardware_msg_data *msg_data;
    struct message *msg;
1601
    unsigned int i, time, flags;
1602
    int wait = 0, x, y;
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620

    static const unsigned int messages[] =
    {
        WM_MOUSEMOVE,    /* 0x0001 = MOUSEEVENTF_MOVE */
        WM_LBUTTONDOWN,  /* 0x0002 = MOUSEEVENTF_LEFTDOWN */
        WM_LBUTTONUP,    /* 0x0004 = MOUSEEVENTF_LEFTUP */
        WM_RBUTTONDOWN,  /* 0x0008 = MOUSEEVENTF_RIGHTDOWN */
        WM_RBUTTONUP,    /* 0x0010 = MOUSEEVENTF_RIGHTUP */
        WM_MBUTTONDOWN,  /* 0x0020 = MOUSEEVENTF_MIDDLEDOWN */
        WM_MBUTTONUP,    /* 0x0040 = MOUSEEVENTF_MIDDLEUP */
        WM_XBUTTONDOWN,  /* 0x0080 = MOUSEEVENTF_XDOWN */
        WM_XBUTTONUP,    /* 0x0100 = MOUSEEVENTF_XUP */
        0,               /* 0x0200 = unused */
        0,               /* 0x0400 = unused */
        WM_MOUSEWHEEL,   /* 0x0800 = MOUSEEVENTF_WHEEL */
        WM_MOUSEHWHEEL   /* 0x1000 = MOUSEEVENTF_HWHEEL */
    };

1621
    desktop->cursor.last_change = get_tick_count();
1622 1623
    flags = input->mouse.flags;
    time  = input->mouse.time;
1624
    if (!time) time = desktop->cursor.last_change;
1625 1626 1627 1628 1629 1630 1631 1632

    if (flags & MOUSEEVENTF_MOVE)
    {
        if (flags & MOUSEEVENTF_ABSOLUTE)
        {
            x = input->mouse.x;
            y = input->mouse.y;
            if (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE) &&
1633
                x == desktop->cursor.x && y == desktop->cursor.y)
1634 1635 1636 1637
                flags &= ~MOUSEEVENTF_MOVE;
        }
        else
        {
1638 1639
            x = desktop->cursor.x + input->mouse.x;
            y = desktop->cursor.y + input->mouse.y;
1640 1641 1642
        }
    }
    else
1643
    {
1644 1645
        x = desktop->cursor.x;
        y = desktop->cursor.y;
1646 1647
    }

1648 1649
    if ((device = current->process->rawinput_mouse))
    {
1650 1651
        if (!(msg = alloc_hardware_message( input->mouse.info, time ))) return 0;
        msg_data = msg->data;
1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666

        msg->win       = device->target;
        msg->msg       = WM_INPUT;
        msg->wparam    = RIM_INPUT;
        msg->lparam    = 0;

        msg_data->flags               = flags;
        msg_data->rawinput.type       = RIM_TYPEMOUSE;
        msg_data->rawinput.mouse.x    = x - desktop->cursor.x;
        msg_data->rawinput.mouse.y    = y - desktop->cursor.y;
        msg_data->rawinput.mouse.data = input->mouse.data;

        queue_hardware_message( desktop, msg, 0 );
    }

1667
    for (i = 0; i < ARRAY_SIZE( messages ); i++)
1668 1669 1670
    {
        if (!messages[i]) continue;
        if (!(flags & (1 << i))) continue;
1671
        flags &= ~(1 << i);
1672

1673 1674
        if (!(msg = alloc_hardware_message( input->mouse.info, time ))) return 0;
        msg_data = msg->data;
1675 1676 1677 1678 1679

        msg->win       = get_user_full_handle( win );
        msg->msg       = messages[i];
        msg->wparam    = input->mouse.data << 16;
        msg->lparam    = 0;
1680 1681
        msg->x         = x;
        msg->y         = y;
1682
        if (hook_flags & SEND_HWMSG_INJECTED) msg_data->flags = LLMHF_INJECTED;
1683

1684
        /* specify a sender only when sending the last message */
1685
        if (!(flags & ((1 << ARRAY_SIZE( messages )) - 1)))
1686 1687
        {
            if (!(wait = send_hook_ll_message( desktop, msg, input, sender )))
1688
                queue_hardware_message( desktop, msg, 0 );
1689 1690
        }
        else if (!send_hook_ll_message( desktop, msg, input, NULL ))
1691
            queue_hardware_message( desktop, msg, 0 );
1692
    }
1693
    return wait;
1694 1695 1696
}

/* queue a hardware message for a keyboard event */
1697 1698
static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
                                   unsigned int hook_flags, struct msg_queue *sender )
1699
{
1700
    const struct rawinput_device *device;
1701 1702 1703
    struct hardware_msg_data *msg_data;
    struct message *msg;
    unsigned char vkey = input->kbd.vkey;
1704
    unsigned int message_code, time;
1705
    int wait;
1706

1707
    if (!(time = input->kbd.time)) time = get_tick_count();
1708

1709
    if (!(input->kbd.flags & KEYEVENTF_UNICODE))
1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730
    {
        switch (vkey)
        {
        case VK_MENU:
        case VK_LMENU:
        case VK_RMENU:
            vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
            break;
        case VK_CONTROL:
        case VK_LCONTROL:
        case VK_RCONTROL:
            vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
            break;
        case VK_SHIFT:
        case VK_LSHIFT:
        case VK_RSHIFT:
            vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
            break;
        }
    }

1731
    message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_KEYUP : WM_KEYDOWN;
1732 1733 1734 1735 1736 1737 1738 1739 1740
    switch (vkey)
    {
    case VK_LMENU:
    case VK_RMENU:
        if (input->kbd.flags & KEYEVENTF_KEYUP)
        {
            /* send WM_SYSKEYUP if Alt still pressed and no other key in between */
            /* we use 0x02 as a flag to track if some other SYSKEYUP was sent already */
            if ((desktop->keystate[VK_MENU] & 0x82) != 0x82) break;
1741
            message_code = WM_SYSKEYUP;
1742 1743 1744 1745 1746 1747
            desktop->keystate[VK_MENU] &= ~0x02;
        }
        else
        {
            /* send WM_SYSKEYDOWN for Alt except with Ctrl */
            if (desktop->keystate[VK_CONTROL] & 0x80) break;
1748
            message_code = WM_SYSKEYDOWN;
1749 1750 1751 1752 1753 1754 1755 1756 1757
            desktop->keystate[VK_MENU] |= 0x02;
        }
        break;

    case VK_LCONTROL:
    case VK_RCONTROL:
        /* send WM_SYSKEYUP on release if Alt still pressed */
        if (!(input->kbd.flags & KEYEVENTF_KEYUP)) break;
        if (!(desktop->keystate[VK_MENU] & 0x80)) break;
1758
        message_code = WM_SYSKEYUP;
1759 1760 1761 1762 1763 1764 1765 1766 1767
        desktop->keystate[VK_MENU] &= ~0x02;
        break;

    default:
        /* send WM_SYSKEY for Alt-anykey and for F10 */
        if (desktop->keystate[VK_CONTROL] & 0x80) break;
        if (!(desktop->keystate[VK_MENU] & 0x80)) break;
        /* fall through */
    case VK_F10:
1768
        message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_SYSKEYUP : WM_SYSKEYDOWN;
1769 1770 1771
        desktop->keystate[VK_MENU] &= ~0x02;
        break;
    }
1772

1773 1774 1775
    if (!(msg = alloc_hardware_message( input->kbd.info, time ))) return 0;
    msg_data = msg->data;

1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812
    if ((device = current->process->rawinput_kbd))
    {
        msg->win       = device->target;
        msg->msg       = WM_INPUT;
        msg->wparam    = RIM_INPUT;

        msg_data->flags                = input->kbd.flags;
        msg_data->rawinput.type        = RIM_TYPEKEYBOARD;
        msg_data->rawinput.kbd.message = message_code;
        msg_data->rawinput.kbd.vkey    = vkey;
        msg_data->rawinput.kbd.scan    = input->kbd.scan;

        queue_hardware_message( desktop, msg, 0 );
    }

    msg->win       = get_user_full_handle( win );
    msg->msg       = message_code;
    msg->lparam    = (input->kbd.scan << 16) | 1u; /* repeat count */
    if (hook_flags & SEND_HWMSG_INJECTED) msg_data->flags = LLKHF_INJECTED;

    if (input->kbd.flags & KEYEVENTF_UNICODE)
    {
        msg->wparam = VK_PACKET;
    }
    else
    {
        unsigned int flags = 0;
        if (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
        /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
        if (input->kbd.flags & KEYEVENTF_KEYUP) flags |= KF_REPEAT | KF_UP;
        else if (desktop->keystate[vkey] & 0x80) flags |= KF_REPEAT;

        msg->wparam = vkey;
        msg->lparam |= flags << 16;
        msg_data->flags |= (flags & (KF_EXTENDED | KF_ALTDOWN | KF_UP)) >> 8;
    }

1813
    if (!(wait = send_hook_ll_message( desktop, msg, input, sender )))
1814
        queue_hardware_message( desktop, msg, 1 );
1815

1816
    return wait;
1817 1818 1819 1820 1821 1822 1823 1824
}

/* queue a hardware message for a custom type of event */
static void queue_custom_hardware_message( struct desktop *desktop, user_handle_t win,
                                           const hw_input_t *input )
{
    struct message *msg;

1825
    if (!(msg = alloc_hardware_message( 0, get_tick_count() ))) return;
1826 1827 1828 1829 1830

    msg->win       = get_user_full_handle( win );
    msg->msg       = input->hw.msg;
    msg->wparam    = 0;
    msg->lparam    = input->hw.lparam;
1831 1832
    msg->x         = desktop->cursor.x;
    msg->y         = desktop->cursor.y;
1833

1834
    queue_hardware_message( desktop, msg, 1 );
1835 1836
}

1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
/* check message filter for a hardware message */
static int check_hw_message_filter( user_handle_t win, unsigned int msg_code,
                                    user_handle_t filter_win, unsigned int first, unsigned int last )
{
    if (msg_code >= WM_KEYFIRST && msg_code <= WM_KEYLAST)
    {
        /* we can only test the window for a keyboard message since the
         * dest window for a mouse message depends on hittest */
        if (filter_win && win != filter_win && !is_child_window( filter_win, win ))
            return 0;
        /* the message code is final for a keyboard message, we can simply check it */
        return check_msg_filter( msg_code, first, last );
    }
    else  /* mouse message */
    {
        /* we need to check all possible values that the message can have in the end */

        if (check_msg_filter( msg_code, first, last )) return 1;
        if (msg_code == WM_MOUSEWHEEL) return 0;  /* no other possible value for this one */

        /* all other messages can become non-client messages */
        if (check_msg_filter( msg_code + (WM_NCMOUSEFIRST - WM_MOUSEFIRST), first, last )) return 1;

        /* clicks can become double-clicks or non-client double-clicks */
        if (msg_code == WM_LBUTTONDOWN || msg_code == WM_MBUTTONDOWN ||
            msg_code == WM_RBUTTONDOWN || msg_code == WM_XBUTTONDOWN)
        {
            if (check_msg_filter( msg_code + (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN), first, last )) return 1;
            if (check_msg_filter( msg_code + (WM_NCLBUTTONDBLCLK - WM_LBUTTONDOWN), first, last )) return 1;
        }
        return 0;
    }
}


1872
/* find a hardware message for the given queue */
1873
static int get_hardware_message( struct thread *thread, unsigned int hw_id, user_handle_t filter_win,
1874 1875
                                 unsigned int first, unsigned int last, unsigned int flags,
                                 struct get_message_reply *reply )
1876 1877 1878
{
    struct thread_input *input = thread->queue->input;
    struct thread *win_thread;
1879
    struct list *ptr;
1880 1881
    user_handle_t win;
    int clear_bits, got_one = 0;
1882
    unsigned int msg_code;
1883

1884 1885
    ptr = list_head( &input->msg_list );
    if (hw_id)
1886
    {
1887 1888 1889 1890 1891 1892 1893 1894
        while (ptr)
        {
            struct message *msg = LIST_ENTRY( ptr, struct message, entry );
            if (msg->unique_id == hw_id) break;
            ptr = list_next( &input->msg_list, ptr );
        }
        if (!ptr) ptr = list_head( &input->msg_list );
        else ptr = list_next( &input->msg_list, ptr );  /* start from the next one */
1895
    }
1896 1897

    if (ptr == list_head( &input->msg_list ))
1898
        clear_bits = QS_INPUT;
1899 1900 1901
    else
        clear_bits = 0;  /* don't clear bits if we don't go through the whole list */

1902
    while (ptr)
1903
    {
1904
        struct message *msg = LIST_ENTRY( ptr, struct message, entry );
1905 1906
        struct hardware_msg_data *data = msg->data;

1907
        ptr = list_next( &input->msg_list, ptr );
1908 1909
        win = find_hardware_message_window( input->desktop, input, msg, &msg_code, &win_thread );
        if (!win || !win_thread)
1910 1911
        {
            /* no window at all, remove it */
1912
            update_input_key_state( input->desktop, input->keystate, msg );
1913
            list_remove( &msg->entry );
1914 1915 1916 1917 1918
            free_message( msg );
            continue;
        }
        if (win_thread != thread)
        {
1919 1920 1921 1922 1923 1924 1925 1926 1927
            if (win_thread->queue->input == input)
            {
                /* wake the other thread */
                set_queue_bits( win_thread->queue, get_hardware_msg_bit(msg) );
                got_one = 1;
            }
            else
            {
                /* for another thread input, drop it */
1928
                update_input_key_state( input->desktop, input->keystate, msg );
1929 1930 1931
                list_remove( &msg->entry );
                free_message( msg );
            }
1932 1933 1934
            release_object( win_thread );
            continue;
        }
1935 1936
        release_object( win_thread );

1937
        /* if we already got a message for another thread, or if it doesn't
1938 1939
         * match the filter we skip it */
        if (got_one || !check_hw_message_filter( win, msg_code, filter_win, first, last ))
1940 1941 1942 1943 1944
        {
            clear_bits &= ~get_hardware_msg_bit( msg );
            continue;
        }
        /* now we can return it */
1945
        if (!msg->unique_id) msg->unique_id = get_unique_id();
1946 1947
        reply->type   = MSG_HARDWARE;
        reply->win    = win;
1948
        reply->msg    = msg_code;
1949 1950
        reply->wparam = msg->wparam;
        reply->lparam = msg->lparam;
1951 1952
        reply->x      = msg->x;
        reply->y      = msg->y;
1953
        reply->time   = msg->time;
1954 1955 1956

        data->hw_id = msg->unique_id;
        set_reply_data( msg->data, msg->data_size );
1957
        if (msg->msg == WM_INPUT && (flags & PM_REMOVE))
1958
            release_hardware_message( current->queue, data->hw_id, 1 );
1959 1960 1961 1962 1963 1964
        return 1;
    }
    /* nothing found, clear the hardware queue bits */
    clear_queue_bits( thread->queue, clear_bits );
    return 0;
}
1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981

/* increment (or decrement if 'incr' is negative) the queue paint count */
void inc_queue_paint_count( struct thread *thread, int incr )
{
    struct msg_queue *queue = thread->queue;

    assert( queue );

    if ((queue->paint_count += incr) < 0) queue->paint_count = 0;

    if (queue->paint_count)
        set_queue_bits( queue, QS_PAINT );
    else
        clear_queue_bits( queue, QS_PAINT );
}


1982
/* remove all messages and timers belonging to a certain window */
1983
void queue_cleanup_window( struct thread *thread, user_handle_t win )
1984
{
1985
    struct msg_queue *queue = thread->queue;
1986
    struct list *ptr;
1987
    int i;
1988

1989 1990
    if (!queue) return;

1991
    /* remove timers */
1992 1993 1994

    ptr = list_head( &queue->pending_timers );
    while (ptr)
1995
    {
1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007
        struct list *next = list_next( &queue->pending_timers, ptr );
        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
        if (timer->win == win) free_timer( queue, timer );
        ptr = next;
    }
    ptr = list_head( &queue->expired_timers );
    while (ptr)
    {
        struct list *next = list_next( &queue->expired_timers, ptr );
        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
        if (timer->win == win) free_timer( queue, timer );
        ptr = next;
2008 2009
    }

2010 2011
    /* remove messages */
    for (i = 0; i < NB_MSG_KINDS; i++)
2012
    {
2013 2014 2015
        struct list *ptr, *next;

        LIST_FOR_EACH_SAFE( ptr, next, &queue->msg_list[i] )
2016
        {
2017
            struct message *msg = LIST_ENTRY( ptr, struct message, entry );
2018 2019 2020 2021 2022 2023 2024 2025 2026
            if (msg->win == win)
            {
                if (msg->msg == WM_QUIT && !queue->quit_message)
                {
                    queue->quit_message = 1;
                    queue->exit_code = msg->wparam;
                }
                remove_queue_message( queue, msg, i );
            }
2027
        }
2028
    }
2029 2030

    thread_input_cleanup_window( queue, win );
2031 2032
}

2033
/* post a message to a window */
2034
void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam )
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051
{
    struct message *msg;
    struct thread *thread = get_window_thread( win );

    if (!thread) return;

    if (thread->queue && (msg = mem_alloc( sizeof(*msg) )))
    {
        msg->type      = MSG_POSTED;
        msg->win       = get_user_full_handle( win );
        msg->msg       = message;
        msg->wparam    = wparam;
        msg->lparam    = lparam;
        msg->result    = NULL;
        msg->data      = NULL;
        msg->data_size = 0;

2052 2053
        get_message_defaults( thread->queue, &msg->x, &msg->y, &msg->time );

2054
        list_add_tail( &thread->queue->msg_list[POST_MESSAGE], &msg->entry );
2055
        set_queue_bits( thread->queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
2056 2057 2058 2059 2060
        if (message == WM_HOTKEY)
        {
            set_queue_bits( thread->queue, QS_HOTKEY );
            thread->queue->hotkey_count++;
        }
2061 2062 2063 2064
    }
    release_object( thread );
}

2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091
/* send a notify message to a window */
void send_notify_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam )
{
    struct message *msg;
    struct thread *thread = get_window_thread( win );

    if (!thread) return;

    if (thread->queue && (msg = mem_alloc( sizeof(*msg) )))
    {
        msg->type      = MSG_NOTIFY;
        msg->win       = get_user_full_handle( win );
        msg->msg       = message;
        msg->wparam    = wparam;
        msg->lparam    = lparam;
        msg->result    = NULL;
        msg->data      = NULL;
        msg->data_size = 0;

        get_message_defaults( thread->queue, &msg->x, &msg->y, &msg->time );

        list_add_tail( &thread->queue->msg_list[SEND_MESSAGE], &msg->entry );
        set_queue_bits( thread->queue, QS_SENDMESSAGE );
    }
    release_object( thread );
}

2092 2093 2094
/* post a win event */
void post_win_event( struct thread *thread, unsigned int event,
                     user_handle_t win, unsigned int object_id,
2095
                     unsigned int child_id, client_ptr_t hook_proc,
2096
                     const WCHAR *module, data_size_t module_size,
2097 2098 2099 2100 2101 2102
                     user_handle_t hook)
{
    struct message *msg;

    if (thread->queue && (msg = mem_alloc( sizeof(*msg) )))
    {
2103 2104
        struct winevent_msg_data *data;

2105 2106 2107 2108 2109 2110 2111 2112
        msg->type      = MSG_WINEVENT;
        msg->win       = get_user_full_handle( win );
        msg->msg       = event;
        msg->wparam    = object_id;
        msg->lparam    = child_id;
        msg->time      = get_tick_count();
        msg->result    = NULL;

2113
        if ((data = malloc( sizeof(*data) + module_size )))
2114
        {
2115 2116 2117 2118 2119 2120 2121
            data->hook = hook;
            data->tid  = get_thread_id( current );
            data->hook_proc = hook_proc;
            memcpy( data + 1, module, module_size );

            msg->data = data;
            msg->data_size = sizeof(*data) + module_size;
2122 2123

            if (debug_level > 1)
2124
                fprintf( stderr, "post_win_event: tid %04x event %04x win %08x object_id %d child_id %d\n",
2125
                         get_thread_id(thread), event, win, object_id, child_id );
2126
            list_add_tail( &thread->queue->msg_list[SEND_MESSAGE], &msg->entry );
2127 2128 2129 2130 2131 2132
            set_queue_bits( thread->queue, QS_SENDMESSAGE );
        }
        else
            free( msg );
    }
}
2133

2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148
/* free all hotkeys on a desktop, optionally filtering by window */
void free_hotkeys( struct desktop *desktop, user_handle_t window )
{
    struct hotkey *hotkey, *hotkey2;

    LIST_FOR_EACH_ENTRY_SAFE( hotkey, hotkey2, &desktop->hotkeys, struct hotkey, entry )
    {
        if (!window || hotkey->win == window)
        {
            list_remove( &hotkey->entry );
            free( hotkey );
        }
    }
}

2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164

/* check if the thread owning the window is hung */
DECL_HANDLER(is_window_hung)
{
    struct thread *thread;

    thread = get_window_thread( req->win );
    if (thread)
    {
        reply->is_hung = is_queue_hung( thread->queue );
        release_object( thread );
    }
    else reply->is_hung = 0;
}


2165 2166 2167
/* get the message queue of the current thread */
DECL_HANDLER(get_msg_queue)
{
2168
    struct msg_queue *queue = get_current_queue();
2169

2170 2171
    reply->handle = 0;
    if (queue) reply->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
2172 2173
}

2174

2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191
/* set the file descriptor associated to the current thread queue */
DECL_HANDLER(set_queue_fd)
{
    struct msg_queue *queue = get_current_queue();
    struct file *file;
    int unix_fd;

    if (queue->fd)  /* fd can only be set once */
    {
        set_error( STATUS_ACCESS_DENIED );
        return;
    }
    if (!(file = get_file_obj( current->process, req->handle, SYNCHRONIZE ))) return;

    if ((unix_fd = get_file_unix_fd( file )) != -1)
    {
        if ((unix_fd = dup( unix_fd )) != -1)
2192
            queue->fd = create_anonymous_fd( &msg_queue_fd_ops, unix_fd, &queue->obj, 0 );
2193 2194 2195 2196 2197 2198 2199
        else
            file_set_error();
    }
    release_object( file );
}


2200 2201 2202 2203 2204 2205 2206 2207 2208
/* set the current message queue wakeup mask */
DECL_HANDLER(set_queue_mask)
{
    struct msg_queue *queue = get_current_queue();

    if (queue)
    {
        queue->wake_mask    = req->wake_mask;
        queue->changed_mask = req->changed_mask;
2209 2210
        reply->wake_bits    = queue->wake_bits;
        reply->changed_bits = queue->changed_bits;
2211 2212 2213
        if (is_signaled( queue ))
        {
            /* if skip wait is set, do what would have been done in the subsequent wait */
2214
            if (req->skip_wait) queue->wake_mask = queue->changed_mask = 0;
2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226
            else wake_up( &queue->obj, 0 );
        }
    }
}


/* get the current message queue status */
DECL_HANDLER(get_queue_status)
{
    struct msg_queue *queue = current->queue;
    if (queue)
    {
2227 2228
        reply->wake_bits    = queue->wake_bits;
        reply->changed_bits = queue->changed_bits;
2229
        queue->changed_bits &= ~req->clear_bits;
2230
    }
2231
    else reply->wake_bits = reply->changed_bits = 0;
2232 2233 2234 2235 2236 2237 2238 2239
}


/* send a message to a thread queue */
DECL_HANDLER(send_message)
{
    struct message *msg;
    struct msg_queue *send_queue = get_current_queue();
2240 2241
    struct msg_queue *recv_queue = NULL;
    struct thread *thread = NULL;
2242

2243
    if (!(thread = get_thread_from_id( req->id ))) return;
2244

2245
    if (!(recv_queue = thread->queue))
2246 2247 2248 2249 2250
    {
        set_error( STATUS_INVALID_PARAMETER );
        release_object( thread );
        return;
    }
2251
    if ((req->flags & SEND_MSG_ABORT_IF_HUNG) && is_queue_hung(recv_queue))
2252 2253 2254 2255 2256
    {
        set_error( STATUS_TIMEOUT );
        release_object( thread );
        return;
    }
2257 2258 2259

    if ((msg = mem_alloc( sizeof(*msg) )))
    {
2260
        msg->type      = req->type;
2261
        msg->win       = get_user_full_handle( req->win );
2262 2263 2264 2265 2266
        msg->msg       = req->msg;
        msg->wparam    = req->wparam;
        msg->lparam    = req->lparam;
        msg->result    = NULL;
        msg->data      = NULL;
2267 2268
        msg->data_size = get_req_data_size();

2269 2270
        get_message_defaults( recv_queue, &msg->x, &msg->y, &msg->time );

2271 2272 2273 2274 2275 2276
        if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size )))
        {
            free( msg );
            release_object( thread );
            return;
        }
2277 2278

        switch(msg->type)
2279
        {
2280
        case MSG_OTHER_PROCESS:
2281 2282 2283
        case MSG_ASCII:
        case MSG_UNICODE:
        case MSG_CALLBACK:
2284
            if (!(msg->result = alloc_message_result( send_queue, recv_queue, msg, req->timeout )))
2285
            {
2286
                free_message( msg );
2287
                break;
2288
            }
2289 2290
            /* fall through */
        case MSG_NOTIFY:
2291
            list_add_tail( &recv_queue->msg_list[SEND_MESSAGE], &msg->entry );
2292 2293 2294
            set_queue_bits( recv_queue, QS_SENDMESSAGE );
            break;
        case MSG_POSTED:
2295
            list_add_tail( &recv_queue->msg_list[POST_MESSAGE], &msg->entry );
2296
            set_queue_bits( recv_queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
2297 2298 2299 2300 2301
            if (msg->msg == WM_HOTKEY)
            {
                set_queue_bits( recv_queue, QS_HOTKEY );
                recv_queue->hotkey_count++;
            }
2302
            break;
2303
        case MSG_HARDWARE:  /* should use send_hardware_message instead */
2304
        case MSG_CALLBACK_RESULT:  /* cannot send this one */
2305
        case MSG_HOOK_LL:  /* generated internally */
2306 2307
        default:
            set_error( STATUS_INVALID_PARAMETER );
2308
            free( msg );
2309
            break;
2310 2311
        }
    }
2312 2313 2314 2315 2316 2317 2318
    release_object( thread );
}

/* send a hardware message to a thread queue */
DECL_HANDLER(send_hardware_message)
{
    struct thread *thread = NULL;
2319
    struct desktop *desktop;
2320
    struct msg_queue *sender = get_current_queue();
2321 2322 2323
    data_size_t size = min( 256, get_reply_max_size() );

    if (!(desktop = get_thread_desktop( current, 0 ))) return;
2324

2325
    if (req->win)
2326
    {
2327
        if (!(thread = get_window_thread( req->win ))) return;
2328 2329 2330 2331 2332 2333
        if (desktop != thread->queue->input->desktop)
        {
            /* don't allow queuing events to a different desktop */
            release_object( desktop );
            return;
        }
2334
    }
2335

2336 2337 2338
    reply->prev_x = desktop->cursor.x;
    reply->prev_y = desktop->cursor.y;

2339
    switch (req->input.type)
2340
    {
2341
    case INPUT_MOUSE:
2342
        reply->wait = queue_mouse_message( desktop, req->win, &req->input, req->flags, sender );
2343 2344
        break;
    case INPUT_KEYBOARD:
2345
        reply->wait = queue_keyboard_message( desktop, req->win, &req->input, req->flags, sender );
2346 2347 2348 2349 2350 2351
        break;
    case INPUT_HARDWARE:
        queue_custom_hardware_message( desktop, req->win, &req->input );
        break;
    default:
        set_error( STATUS_INVALID_PARAMETER );
2352
    }
2353
    if (thread) release_object( thread );
2354 2355 2356

    reply->new_x = desktop->cursor.x;
    reply->new_y = desktop->cursor.y;
2357
    set_reply_data( desktop->keystate, size );
2358
    release_object( desktop );
2359 2360
}

2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372
/* post a quit message to the current queue */
DECL_HANDLER(post_quit_message)
{
    struct msg_queue *queue = get_current_queue();

    if (!queue)
        return;

    queue->quit_message = 1;
    queue->exit_code = req->exit_code;
    set_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
}
2373

2374 2375 2376 2377
/* get a message from the current queue */
DECL_HANDLER(get_message)
{
    struct timer *timer;
2378
    struct list *ptr;
2379
    struct msg_queue *queue = get_current_queue();
2380
    user_handle_t get_win = get_user_full_handle( req->get_win );
2381
    unsigned int filter = req->flags >> 16;
2382

2383 2384
    reply->active_hooks = get_active_hooks();

2385
    if (!queue) return;
2386
    queue->last_get_msg = current_time;
2387
    if (!filter) filter = QS_ALLINPUT;
2388 2389

    /* first check for sent messages */
2390
    if ((ptr = list_head( &queue->msg_list[SEND_MESSAGE] )))
2391
    {
2392
        struct message *msg = LIST_ENTRY( ptr, struct message, entry );
2393
        receive_message( queue, msg, reply );
2394 2395 2396
        return;
    }

2397
    /* clear changed bits so we can wait on them if we don't find a message */
2398 2399 2400 2401 2402 2403 2404
    if (filter & QS_POSTMESSAGE)
    {
        queue->changed_bits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER);
        if (req->get_first == 0 && req->get_last == ~0U) queue->changed_bits &= ~QS_ALLPOSTMESSAGE;
    }
    if (filter & QS_INPUT) queue->changed_bits &= ~QS_INPUT;
    if (filter & QS_PAINT) queue->changed_bits &= ~QS_PAINT;
2405

2406
    /* then check for posted messages */
2407 2408
    if ((filter & QS_POSTMESSAGE) &&
        get_posted_message( queue, get_win, req->get_first, req->get_last, req->flags, reply ))
2409 2410
        return;

2411 2412 2413 2414 2415
    if ((filter & QS_HOTKEY) && queue->hotkey_count &&
        req->get_first <= WM_HOTKEY && req->get_last >= WM_HOTKEY &&
        get_posted_message( queue, get_win, WM_HOTKEY, WM_HOTKEY, req->flags, reply ))
        return;

2416 2417
    /* only check for quit messages if not posted messages pending */
    if ((filter & QS_POSTMESSAGE) && get_quit_message( queue, req->flags, reply ))
2418 2419
        return;

2420
    /* then check for any raw hardware message */
2421 2422
    if ((filter & QS_INPUT) &&
        filter_contains_hw_range( req->get_first, req->get_last ) &&
2423
        get_hardware_message( current, req->hw_id, get_win, req->get_first, req->get_last, req->flags, reply ))
2424
        return;
2425 2426

    /* now check for WM_PAINT */
2427 2428
    if ((filter & QS_PAINT) &&
        queue->paint_count &&
2429
        check_msg_filter( WM_PAINT, req->get_first, req->get_last ) &&
2430 2431 2432 2433 2434 2435
        (reply->win = find_window_to_repaint( get_win, current )))
    {
        reply->type   = MSG_POSTED;
        reply->msg    = WM_PAINT;
        reply->wparam = 0;
        reply->lparam = 0;
2436
        get_message_defaults( queue, &reply->x, &reply->y, &reply->time );
2437 2438 2439 2440
        return;
    }

    /* now check for timer */
2441 2442 2443
    if ((filter & QS_TIMER) &&
        (timer = find_expired_timer( queue, get_win, req->get_first,
                                     req->get_last, (req->flags & PM_REMOVE) )))
2444
    {
2445 2446 2447 2448 2449
        reply->type   = MSG_POSTED;
        reply->win    = timer->win;
        reply->msg    = timer->msg;
        reply->wparam = timer->id;
        reply->lparam = timer->lparam;
2450
        get_message_defaults( queue, &reply->x, &reply->y, &reply->time );
2451 2452
        if (!(req->flags & PM_NOYIELD) && current->process->idle_event)
            set_event( current->process->idle_event );
2453 2454 2455
        return;
    }

2456
    if (get_win == -1 && current->process->idle_event) set_event( current->process->idle_event );
2457 2458
    queue->wake_mask = req->wake_mask;
    queue->changed_mask = req->changed_mask;
2459 2460 2461 2462 2463 2464 2465
    set_error( STATUS_PENDING );  /* FIXME */
}


/* reply to a sent message */
DECL_HANDLER(reply_message)
{
2466
    if (!current->queue) set_error( STATUS_ACCESS_DENIED );
2467 2468 2469
    else if (current->queue->recv_result)
        reply_message( current->queue, req->result, 0, req->remove,
                       get_req_data(), get_req_data_size() );
2470 2471 2472
}


2473 2474 2475 2476
/* accept the current hardware message */
DECL_HANDLER(accept_hardware_message)
{
    if (current->queue)
2477
        release_hardware_message( current->queue, req->hw_id, req->remove );
2478 2479
    else
        set_error( STATUS_ACCESS_DENIED );
2480 2481 2482
}


2483 2484 2485
/* retrieve the reply for the last message sent */
DECL_HANDLER(get_message_reply)
{
2486 2487
    struct message_result *result;
    struct list *entry;
2488
    struct msg_queue *queue = current->queue;
2489

2490 2491 2492
    if (queue)
    {
        set_error( STATUS_PENDING );
2493
        reply->result = 0;
2494

2495 2496 2497 2498
        if (!(entry = list_head( &queue->send_result ))) return;  /* no reply ready */

        result = LIST_ENTRY( entry, struct message_result, sender_entry );
        if (result->replied || req->cancel)
2499
        {
2500 2501
            if (result->replied)
            {
2502
                reply->result = result->result;
2503 2504 2505
                set_error( result->error );
                if (result->data)
                {
2506
                    data_size_t data_len = min( result->data_size, get_reply_max_size() );
2507
                    set_reply_data_ptr( result->data, data_len );
2508 2509 2510 2511
                    result->data = NULL;
                    result->data_size = 0;
                }
            }
2512 2513 2514 2515 2516 2517 2518
            remove_result_from_sender( result );

            entry = list_head( &queue->send_result );
            if (!entry) clear_queue_bits( queue, QS_SMRESULT );
            else
            {
                result = LIST_ENTRY( entry, struct message_result, sender_entry );
2519 2520
                if (result->replied) set_queue_bits( queue, QS_SMRESULT );
                else clear_queue_bits( queue, QS_SMRESULT );
2521
            }
2522 2523
        }
    }
2524
    else set_error( STATUS_ACCESS_DENIED );
2525 2526 2527 2528 2529 2530 2531
}


/* set a window timer */
DECL_HANDLER(set_win_timer)
{
    struct timer *timer;
2532 2533 2534
    struct msg_queue *queue;
    struct thread *thread = NULL;
    user_handle_t win = 0;
2535
    lparam_t id = req->id;
2536

2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556
    if (req->win)
    {
        if (!(win = get_user_full_handle( req->win )) || !(thread = get_window_thread( win )))
        {
            set_error( STATUS_INVALID_HANDLE );
            return;
        }
        if (thread->process != current->process)
        {
            release_object( thread );
            set_error( STATUS_ACCESS_DENIED );
            return;
        }
        queue = thread->queue;
        /* remove it if it existed already */
        if ((timer = find_timer( queue, win, req->msg, id ))) free_timer( queue, timer );
    }
    else
    {
        queue = get_current_queue();
2557
        /* look for a timer with this id */
2558
        if (id && (timer = find_timer( queue, 0, req->msg, id )))
2559
        {
2560 2561 2562 2563 2564
            /* free and reuse id */
            free_timer( queue, timer );
        }
        else
        {
2565 2566
            lparam_t end_id = queue->next_timer_id;

2567
            /* find a free id for it */
2568
            while (1)
2569 2570
            {
                id = queue->next_timer_id;
2571
                if (--queue->next_timer_id <= 0x100) queue->next_timer_id = 0x7fff;
2572 2573 2574 2575 2576 2577 2578

                if (!find_timer( queue, 0, req->msg, id )) break;
                if (queue->next_timer_id == end_id)
                {
                    set_win32_error( ERROR_NO_MORE_USER_HANDLES );
                    return;
                }
2579
            }
2580 2581
        }
    }
2582 2583 2584

    if ((timer = set_timer( queue, req->rate )))
    {
2585
        timer->win    = win;
2586
        timer->msg    = req->msg;
2587
        timer->id     = id;
2588
        timer->lparam = req->lparam;
2589
        reply->id     = id;
2590
    }
2591
    if (thread) release_object( thread );
2592 2593 2594 2595 2596
}

/* kill a window timer */
DECL_HANDLER(kill_win_timer)
{
2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615
    struct timer *timer;
    struct thread *thread;
    user_handle_t win = 0;

    if (req->win)
    {
        if (!(win = get_user_full_handle( req->win )) || !(thread = get_window_thread( win )))
        {
            set_error( STATUS_INVALID_HANDLE );
            return;
        }
        if (thread->process != current->process)
        {
            release_object( thread );
            set_error( STATUS_ACCESS_DENIED );
            return;
        }
    }
    else thread = (struct thread *)grab_object( current );
2616

2617 2618 2619
    if (thread->queue && (timer = find_timer( thread->queue, win, req->msg, req->id )))
        free_timer( thread->queue, timer );
    else
2620
        set_error( STATUS_INVALID_PARAMETER );
2621 2622

    release_object( thread );
2623
}
2624

2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637
DECL_HANDLER(register_hotkey)
{
    struct desktop *desktop;
    user_handle_t win_handle = req->window;
    struct hotkey *hotkey;
    struct hotkey *new_hotkey = NULL;
    struct thread *thread;
    const int modifier_flags = MOD_ALT|MOD_CONTROL|MOD_SHIFT|MOD_WIN;

    if (!(desktop = get_thread_desktop( current, 0 ))) return;

    if (win_handle)
    {
2638
        if (!(win_handle = get_valid_window_handle( win_handle )))
2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705
        {
            release_object( desktop );
            return;
        }

        thread = get_window_thread( win_handle );
        if (thread) release_object( thread );

        if (thread != current)
        {
            release_object( desktop );
            set_win32_error( ERROR_WINDOW_OF_OTHER_THREAD );
            return;
        }
    }

    LIST_FOR_EACH_ENTRY( hotkey, &desktop->hotkeys, struct hotkey, entry )
    {
        if (req->vkey == hotkey->vkey &&
            (req->flags & modifier_flags) == (hotkey->flags & modifier_flags))
        {
            release_object( desktop );
            set_win32_error( ERROR_HOTKEY_ALREADY_REGISTERED );
            return;
        }
        if (current->queue == hotkey->queue && win_handle == hotkey->win && req->id == hotkey->id)
            new_hotkey = hotkey;
    }

    if (new_hotkey)
    {
        reply->replaced = 1;
        reply->flags    = new_hotkey->flags;
        reply->vkey     = new_hotkey->vkey;
    }
    else
    {
        new_hotkey = mem_alloc( sizeof(*new_hotkey) );
        if (new_hotkey)
        {
            list_add_tail( &desktop->hotkeys, &new_hotkey->entry );
            new_hotkey->queue  = current->queue;
            new_hotkey->win    = win_handle;
            new_hotkey->id     = req->id;
        }
    }

    if (new_hotkey)
    {
        new_hotkey->flags = req->flags;
        new_hotkey->vkey  = req->vkey;
    }

    release_object( desktop );
}

DECL_HANDLER(unregister_hotkey)
{
    struct desktop *desktop;
    user_handle_t win_handle = req->window;
    struct hotkey *hotkey;
    struct thread *thread;

    if (!(desktop = get_thread_desktop( current, 0 ))) return;

    if (win_handle)
    {
2706
        if (!(win_handle = get_valid_window_handle( win_handle )))
2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739
        {
            release_object( desktop );
            return;
        }

        thread = get_window_thread( win_handle );
        if (thread) release_object( thread );

        if (thread != current)
        {
            release_object( desktop );
            set_win32_error( ERROR_WINDOW_OF_OTHER_THREAD );
            return;
        }
    }

    LIST_FOR_EACH_ENTRY( hotkey, &desktop->hotkeys, struct hotkey, entry )
    {
        if (current->queue == hotkey->queue && win_handle == hotkey->win && req->id == hotkey->id)
            goto found;
    }

    release_object( desktop );
    set_win32_error( ERROR_HOTKEY_NOT_REGISTERED );
    return;

found:
    reply->flags = hotkey->flags;
    reply->vkey  = hotkey->vkey;
    list_remove( &hotkey->entry );
    free( hotkey );
    release_object( desktop );
}
2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754

/* attach (or detach) thread inputs */
DECL_HANDLER(attach_thread_input)
{
    struct thread *thread_from = get_thread_from_id( req->tid_from );
    struct thread *thread_to = get_thread_from_id( req->tid_to );

    if (!thread_from || !thread_to)
    {
        if (thread_from) release_object( thread_from );
        if (thread_to) release_object( thread_to );
        return;
    }
    if (thread_from != thread_to)
    {
2755 2756 2757 2758 2759 2760 2761 2762
        if (req->attach)
        {
            if ((thread_to->queue || thread_to == current) &&
                (thread_from->queue || thread_from == current))
                attach_thread_input( thread_from, thread_to );
            else
                set_error( STATUS_INVALID_PARAMETER );
        }
2763 2764 2765 2766 2767 2768 2769 2770
        else
        {
            if (thread_from->queue && thread_to->queue &&
                thread_from->queue->input == thread_to->queue->input)
                detach_thread_input( thread_from );
            else
                set_error( STATUS_ACCESS_DENIED );
        }
2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781
    }
    else set_error( STATUS_ACCESS_DENIED );
    release_object( thread_from );
    release_object( thread_to );
}


/* get thread input data */
DECL_HANDLER(get_thread_input)
{
    struct thread *thread = NULL;
2782
    struct desktop *desktop;
2783 2784 2785 2786 2787
    struct thread_input *input;

    if (req->tid)
    {
        if (!(thread = get_thread_from_id( req->tid ))) return;
2788 2789 2790 2791 2792
        if (!(desktop = get_thread_desktop( thread, 0 )))
        {
            release_object( thread );
            return;
        }
2793 2794
        input = thread->queue ? thread->queue->input : NULL;
    }
2795 2796 2797 2798 2799
    else
    {
        if (!(desktop = get_thread_desktop( current, 0 ))) return;
        input = desktop->foreground_input;  /* get the foreground thread info */
    }
2800 2801 2802 2803 2804 2805 2806 2807 2808

    if (input)
    {
        reply->focus      = input->focus;
        reply->capture    = input->capture;
        reply->active     = input->active;
        reply->menu_owner = input->menu_owner;
        reply->move_size  = input->move_size;
        reply->caret      = input->caret;
2809 2810
        reply->cursor     = input->cursor;
        reply->show_count = input->cursor_count;
2811
        reply->rect       = input->caret_rect;
2812
    }
2813

2814
    /* foreground window is active window of foreground thread */
2815
    reply->foreground = desktop->foreground_input ? desktop->foreground_input->active : 0;
2816
    if (thread) release_object( thread );
2817
    release_object( desktop );
2818
}
2819 2820


2821 2822 2823 2824
/* retrieve queue keyboard state for a given thread */
DECL_HANDLER(get_key_state)
{
    struct thread *thread;
2825 2826
    struct desktop *desktop;
    data_size_t size = min( 256, get_reply_max_size() );
2827

2828
    if (!req->tid)  /* get global async key state */
2829
    {
2830
        if (!(desktop = get_thread_desktop( current, 0 ))) return;
2831 2832 2833 2834 2835
        if (req->key >= 0)
        {
            reply->state = desktop->keystate[req->key & 0xff];
            desktop->keystate[req->key & 0xff] &= ~0x40;
        }
2836 2837 2838 2839 2840
        set_reply_data( desktop->keystate, size );
        release_object( desktop );
    }
    else
    {
2841
        unsigned char *keystate;
2842 2843 2844 2845 2846
        if (!(thread = get_thread_from_id( req->tid ))) return;
        if (thread->queue)
        {
            if (req->key >= 0) reply->state = thread->queue->input->keystate[req->key & 0xff];
            set_reply_data( thread->queue->input->keystate, size );
2847 2848
            release_object( thread );
            return;
2849 2850
        }
        release_object( thread );
2851 2852 2853 2854 2855 2856 2857 2858 2859 2860

        /* fallback to desktop keystate */
        if (!(desktop = get_thread_desktop( current, 0 ))) return;
        if (req->key >= 0) reply->state = desktop->keystate[req->key & 0xff] & ~0x40;
        if ((keystate = set_reply_data_size( size )))
        {
            unsigned int i;
            for (i = 0; i < size; i++) keystate[i] = desktop->keystate[i] & ~0x40;
        }
        release_object( desktop );
2861 2862 2863 2864 2865 2866 2867
    }
}


/* set queue keyboard state for a given thread */
DECL_HANDLER(set_key_state)
{
2868 2869 2870
    struct thread *thread;
    struct desktop *desktop;
    data_size_t size = min( 256, get_req_data_size() );
2871

2872
    if (!req->tid)  /* set global async key state */
2873
    {
2874 2875 2876 2877 2878 2879 2880 2881
        if (!(desktop = get_thread_desktop( current, 0 ))) return;
        memcpy( desktop->keystate, get_req_data(), size );
        release_object( desktop );
    }
    else
    {
        if (!(thread = get_thread_from_id( req->tid ))) return;
        if (thread->queue) memcpy( thread->queue->input->keystate, get_req_data(), size );
2882 2883 2884 2885 2886
        if (req->async && (desktop = get_thread_desktop( thread, 0 )))
        {
            memcpy( desktop->keystate, get_req_data(), size );
            release_object( desktop );
        }
2887
        release_object( thread );
2888 2889 2890 2891
    }
}


2892 2893 2894
/* set the system foreground window */
DECL_HANDLER(set_foreground_window)
{
2895 2896
    struct thread *thread = NULL;
    struct desktop *desktop;
2897 2898
    struct msg_queue *queue = get_current_queue();

2899 2900 2901
    if (!(desktop = get_thread_desktop( current, 0 ))) return;
    reply->previous = desktop->foreground_input ? desktop->foreground_input->active : 0;
    reply->send_msg_old = (reply->previous && desktop->foreground_input != queue->input);
2902 2903
    reply->send_msg_new = FALSE;

2904 2905 2906
    if (is_valid_foreground_window( req->handle ) &&
        (thread = get_window_thread( req->handle )) &&
        thread->queue->input->desktop == desktop)
2907
    {
2908
        set_foreground_input( desktop, thread->queue->input );
2909
        reply->send_msg_new = (desktop->foreground_input != queue->input);
2910
    }
2911
    else set_win32_error( ERROR_INVALID_WINDOW_HANDLE );
2912 2913 2914

    if (thread) release_object( thread );
    release_object( desktop );
2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947
}


/* set the current thread focus window */
DECL_HANDLER(set_focus_window)
{
    struct msg_queue *queue = get_current_queue();

    reply->previous = 0;
    if (queue && check_queue_input_window( queue, req->handle ))
    {
        reply->previous = queue->input->focus;
        queue->input->focus = get_user_full_handle( req->handle );
    }
}


/* set the current thread active window */
DECL_HANDLER(set_active_window)
{
    struct msg_queue *queue = get_current_queue();

    reply->previous = 0;
    if (queue && check_queue_input_window( queue, req->handle ))
    {
        if (!req->handle || make_window_active( req->handle ))
        {
            reply->previous = queue->input->active;
            queue->input->active = get_user_full_handle( req->handle );
        }
        else set_error( STATUS_INVALID_HANDLE );
    }
}
2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959


/* set the current thread capture window */
DECL_HANDLER(set_capture_window)
{
    struct msg_queue *queue = get_current_queue();

    reply->previous = reply->full_handle = 0;
    if (queue && check_queue_input_window( queue, req->handle ))
    {
        struct thread_input *input = queue->input;

2960 2961 2962 2963 2964 2965
        /* if in menu mode, reject all requests to change focus, except if the menu bit is set */
        if (input->menu_owner && !(req->flags & CAPTURE_MENU))
        {
            set_error(STATUS_ACCESS_DENIED);
            return;
        }
2966 2967 2968 2969 2970 2971 2972
        reply->previous = input->capture;
        input->capture = get_user_full_handle( req->handle );
        input->menu_owner = (req->flags & CAPTURE_MENU) ? input->capture : 0;
        input->move_size = (req->flags & CAPTURE_MOVESIZE) ? input->capture : 0;
        reply->full_handle = input->capture;
    }
}
2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990


/* Set the current thread caret window */
DECL_HANDLER(set_caret_window)
{
    struct msg_queue *queue = get_current_queue();

    reply->previous = 0;
    if (queue && check_queue_input_window( queue, req->handle ))
    {
        struct thread_input *input = queue->input;

        reply->previous  = input->caret;
        reply->old_rect  = input->caret_rect;
        reply->old_hide  = input->caret_hide;
        reply->old_state = input->caret_state;

        set_caret_window( input, get_user_full_handle(req->handle) );
2991 2992
        input->caret_rect.right  = input->caret_rect.left + req->width;
        input->caret_rect.bottom = input->caret_rect.top + req->height;
2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028
    }
}


/* Set the current thread caret information */
DECL_HANDLER(set_caret_info)
{
    struct msg_queue *queue = get_current_queue();
    struct thread_input *input;

    if (!queue) return;
    input = queue->input;
    reply->full_handle = input->caret;
    reply->old_rect    = input->caret_rect;
    reply->old_hide    = input->caret_hide;
    reply->old_state   = input->caret_state;

    if (req->handle && get_user_full_handle(req->handle) != input->caret)
    {
        set_error( STATUS_ACCESS_DENIED );
        return;
    }
    if (req->flags & SET_CARET_POS)
    {
        input->caret_rect.right  += req->x - input->caret_rect.left;
        input->caret_rect.bottom += req->y - input->caret_rect.top;
        input->caret_rect.left = req->x;
        input->caret_rect.top  = req->y;
    }
    if (req->flags & SET_CARET_HIDE)
    {
        input->caret_hide += req->hide;
        if (input->caret_hide < 0) input->caret_hide = 0;
    }
    if (req->flags & SET_CARET_STATE)
    {
3029 3030 3031 3032 3033 3034 3035 3036 3037
        switch (req->state)
        {
        case CARET_STATE_OFF:    input->caret_state = 0; break;
        case CARET_STATE_ON:     input->caret_state = 1; break;
        case CARET_STATE_TOGGLE: input->caret_state = !input->caret_state; break;
        case CARET_STATE_ON_IF_MOVED:
            if (req->x != reply->old_rect.left || req->y != reply->old_rect.top) input->caret_state = 1;
            break;
        }
3038 3039
    }
}
3040 3041 3042 3043 3044 3045 3046


/* get the time of the last input event */
DECL_HANDLER(get_last_input_time)
{
    reply->time = last_input_time;
}
3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058

/* set/get the current cursor */
DECL_HANDLER(set_cursor)
{
    struct msg_queue *queue = get_current_queue();
    struct thread_input *input;

    if (!queue) return;
    input = queue->input;

    reply->prev_handle = input->cursor;
    reply->prev_count  = input->cursor_count;
3059 3060
    reply->prev_x      = input->desktop->cursor.x;
    reply->prev_y      = input->desktop->cursor.y;
3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075

    if (req->flags & SET_CURSOR_HANDLE)
    {
        if (req->handle && !get_user_object( req->handle, USER_CLIENT ))
        {
            set_win32_error( ERROR_INVALID_CURSOR_HANDLE );
            return;
        }
        input->cursor = req->handle;
    }
    if (req->flags & SET_CURSOR_COUNT)
    {
        queue->cursor_count += req->show_count;
        input->cursor_count += req->show_count;
    }
3076 3077
    if (req->flags & SET_CURSOR_POS)
    {
3078 3079
        set_cursor_pos( input->desktop, req->x, req->y );
    }
3080
    if (req->flags & (SET_CURSOR_CLIP | SET_CURSOR_NOCLIP))
3081
    {
3082 3083 3084 3085 3086 3087
        struct desktop *desktop = input->desktop;

        /* only the desktop owner can set the message */
        if (req->clip_msg && get_top_window_owner(desktop) == current->process)
            desktop->cursor.clip_msg = req->clip_msg;

3088
        set_clip_rectangle( desktop, (req->flags & SET_CURSOR_NOCLIP) ? NULL : &req->clip, 0 );
3089 3090
    }

3091 3092 3093 3094
    reply->new_x       = input->desktop->cursor.x;
    reply->new_y       = input->desktop->cursor.y;
    reply->new_clip    = input->desktop->cursor.clip;
    reply->last_change = input->desktop->cursor.last_change;
3095
}
3096 3097 3098 3099 3100

DECL_HANDLER(update_rawinput_devices)
{
    const struct rawinput_device *devices = get_req_data();
    unsigned int device_count = get_req_data_size() / sizeof (*devices);
3101
    const struct rawinput_device_entry *e;
3102 3103 3104 3105 3106 3107
    unsigned int i;

    for (i = 0; i < device_count; ++i)
    {
        update_rawinput_device(&devices[i]);
    }
3108 3109 3110

    e = find_rawinput_device( 1, 2 );
    current->process->rawinput_mouse = e ? &e->device : NULL;
3111 3112
    e = find_rawinput_device( 1, 6 );
    current->process->rawinput_kbd   = e ? &e->device : NULL;
3113
}