queue.c 101 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_kernel_obj_list,        /* get_kernel_obj_list */
185
    no_close_handle,           /* close_handle */
186
    msg_queue_destroy          /* destroy */
187 188
};

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

201

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

225
/* pointer to input structure of foreground thread */
226
static unsigned int last_input_time;
227

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

/* set the caret window in a given thread input */
static void set_caret_window( struct thread_input *input, user_handle_t win )
{
234 235 236 237 238 239 240
    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;
    }
241 242 243 244 245
    input->caret             = win;
    input->caret_hide        = 1;
    input->caret_state       = 0;
}

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

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

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

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

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

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

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

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

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

    if (!queue)
330 331 332 333
    {
        thread->queue = create_msg_queue( thread, new_input );
        return thread->queue != NULL;
    }
334 335 336 337 338 339 340
    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;
341 342 343
    return 1;
}

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

351
    if (!(msg = mem_alloc( sizeof(*msg) ))) return NULL;
352 353 354
    if (!(msg_data = mem_alloc( sizeof(*msg_data) )))
    {
        free( msg );
355
        return NULL;
356
    }
357
    memset( msg, 0, sizeof(*msg) );
358
    msg->type      = MSG_HARDWARE;
359
    msg->time      = time;
360 361
    msg->data      = msg_data;
    msg->data_size = sizeof(*msg_data);
362 363 364

    memset( msg_data, 0, sizeof(*msg_data) );
    msg_data->info   = info;
365
    msg_data->source = source;
366 367 368 369 370 371
    return msg;
}

/* set the cursor position and queue the corresponding mouse message */
static void set_cursor_pos( struct desktop *desktop, int x, int y )
{
372
    static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM };
373 374
    struct message *msg;

375
    if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return;
376 377 378 379

    msg->msg = WM_MOUSEMOVE;
    msg->x   = x;
    msg->y   = y;
380
    queue_hardware_message( desktop, msg, 1 );
381 382
}

383 384 385 386 387 388 389 390 391 392
/* 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();
}

393
/* set the cursor clip rectangle */
394
static void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg )
395
{
396
    rectangle_t top_rect;
397
    int x, y;
398 399

    get_top_window_rectangle( desktop, &top_rect );
400 401 402 403 404 405 406 407 408 409 410 411
    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;

412
    if (desktop->cursor.clip_msg && send_clip_msg)
413
        post_desktop_message( desktop, desktop->cursor.clip_msg, rect != NULL, 0 );
414 415

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

421 422 423 424
/* 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;
425
    set_clip_rectangle( desktop, NULL, 1 );
426 427 428
    desktop->foreground_input = input;
}

429 430 431 432 433 434 435 436 437 438 439
/* 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;
440
    if (!queue && !(queue = create_msg_queue( thread, NULL ))) return;
441 442 443 444
    if (queue->hooks) release_object( queue->hooks );
    queue->hooks = hooks;
}

445
/* check the queue status */
446
static inline int is_signaled( struct msg_queue *queue )
447 448 449 450
{
    return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
}

451
/* set some queue bits */
452
static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits )
453
{
454 455
    queue->wake_bits |= bits;
    queue->changed_bits |= bits;
456 457 458
    if (is_signaled( queue )) wake_up( &queue->obj, 0 );
}

459
/* clear some queue bits */
460
static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits )
461 462 463 464 465
{
    queue->wake_bits &= ~bits;
    queue->changed_bits &= ~bits;
}

466
/* check whether msg is a keyboard message */
467
static inline int is_keyboard_msg( struct message *msg )
468 469 470 471
{
    return (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST);
}

472
/* check if message is matched by the filter */
473
static inline int check_msg_filter( unsigned int msg, unsigned int first, unsigned int last )
474 475 476 477
{
    return (msg >= first && msg <= last);
}

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

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

502
/* get the current thread queue, creating it if needed */
503
static inline struct msg_queue *get_current_queue(void)
504 505
{
    struct msg_queue *queue = current->queue;
506
    if (!queue) queue = create_msg_queue( current, NULL );
507 508 509
    return queue;
}

510
/* get a (pseudo-)unique id to tag hardware messages */
511
static inline unsigned int get_unique_id(void)
512 513 514 515 516 517
{
    static unsigned int id;
    if (!++id) id = 1;  /* avoid an id of 0 */
    return id;
}

518
/* try to merge a message with the last in the list; return 1 if successful */
519
static int merge_message( struct thread_input *input, const struct message *msg )
520
{
521
    struct message *prev;
522
    struct list *ptr;
523

524
    if (msg->msg != WM_MOUSEMOVE) return 0;
525 526 527 528 529 530
    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;
531
    if (prev->result) return 0;
532
    if (prev->win && msg->win && prev->win != msg->win) return 0;
533 534 535 536 537
    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;
538 539
    prev->x       = msg->x;
    prev->y       = msg->y;
540
    prev->time    = msg->time;
541 542 543 544
    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;
545
        prev_data->info = msg_data->info;
546
    }
547 548
    list_remove( ptr );
    list_add_tail( &input->msg_list, ptr );
549 550 551
    return 1;
}

552 553 554 555
/* free a result structure */
static void free_result( struct message_result *result )
{
    if (result->timeout) remove_timeout_user( result->timeout );
556
    free( result->data );
557
    if (result->callback_msg) free_message( result->callback_msg );
558 559
    if (result->hardware_msg) free_message( result->hardware_msg );
    if (result->desktop) release_object( result->desktop );
560 561 562
    free( result );
}

563 564 565 566 567 568 569 570 571 572
/* 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 );
}

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

    if (res->hardware_msg)
    {
        if (!error && result)  /* rejected by the hook */
            free_message( res->hardware_msg );
        else
590
            queue_hardware_message( res->desktop, res->hardware_msg, 0 );
591 592 593 594

        res->hardware_msg = NULL;
    }

595 596 597 598 599
    if (res->sender)
    {
        if (res->callback_msg)
        {
            /* queue the callback message in the sender queue */
600 601
            struct callback_msg_data *data = res->callback_msg->data;
            data->result = result;
602
            list_add_tail( &res->sender->msg_list[SEND_MESSAGE], &res->callback_msg->entry );
603 604 605 606 607 608 609 610 611 612 613
            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 );
        }
    }
614
    else if (!res->receiver) free_result( res );
615 616
}

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

631 632 633
/* 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 )
634
{
635
    list_remove( &msg->entry );
636 637 638
    switch(kind)
    {
    case SEND_MESSAGE:
639
        if (list_empty( &queue->msg_list[kind] )) clear_queue_bits( queue, QS_SENDMESSAGE );
640 641
        break;
    case POST_MESSAGE:
642 643
        if (list_empty( &queue->msg_list[kind] ) && !queue->quit_message)
            clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
644 645
        if (msg->msg == WM_HOTKEY && --queue->hotkey_count == 0)
            clear_queue_bits( queue, QS_HOTKEY );
646 647
        break;
    }
648 649 650
    free_message( msg );
}

651 652 653 654 655 656 657 658
/* message timed out without getting a reply */
static void result_timeout( void *private )
{
    struct message_result *result = private;

    assert( !result->replied );

    result->timeout = NULL;
659 660 661 662 663 664 665 666 667 668

    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;
    }
669 670 671 672 673 674
    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,
675
                                                    struct message *msg, timeout_t timeout )
676 677
{
    struct message_result *result = mem_alloc( sizeof(*result) );
678 679
    if (result)
    {
680 681 682 683 684 685 686 687 688 689
        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;
690 691 692 693

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

695 696 697 698 699 700 701 702
            if (!callback_msg)
            {
                free( result );
                return NULL;
            }
            callback_msg->type      = MSG_CALLBACK_RESULT;
            callback_msg->win       = msg->win;
            callback_msg->msg       = msg->msg;
703
            callback_msg->wparam    = 0;
704 705 706
            callback_msg->lparam    = 0;
            callback_msg->time      = get_tick_count();
            callback_msg->result    = NULL;
707 708 709 710 711
            /* 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;
712 713 714 715

            result->callback_msg = callback_msg;
            list_add_head( &send_queue->callback_result, &result->sender_entry );
        }
716 717 718 719 720
        else if (send_queue)
        {
            list_add_head( &send_queue->send_result, &result->sender_entry );
            clear_queue_bits( send_queue, QS_SMRESULT );
        }
721

722 723
        if (timeout != TIMEOUT_INFINITE)
            result->timeout = add_timeout_user( timeout, result_timeout, result );
724 725
    }
    return result;
726 727 728
}

/* receive a message, removing it from the sent queue */
729 730
static void receive_message( struct msg_queue *queue, struct message *msg,
                             struct get_message_reply *reply )
731 732 733
{
    struct message_result *result = msg->result;

734 735 736 737 738 739 740 741 742 743 744
    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;
745 746
    reply->x      = msg->x;
    reply->y      = msg->y;
747 748 749 750
    reply->time   = msg->time;

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

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

/* set the result of the current received message */
764
static void reply_message( struct msg_queue *queue, lparam_t result,
765
                           unsigned int error, int remove, const void *data, data_size_t len )
766 767 768 769 770 771 772
{
    struct message_result *res = queue->recv_result;

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

786 787 788
static int match_window( user_handle_t win, user_handle_t msg_win )
{
    if (!win) return 1;
789
    if (win == -1 || win == 1) return !msg_win;
790 791 792 793
    if (msg_win == win) return 1;
    return is_child_window( win, msg_win );
}

794 795 796 797 798 799 800 801
/* 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 */
802
    LIST_FOR_EACH_ENTRY( msg, &queue->msg_list[POST_MESSAGE], struct message, entry )
803
    {
804
        if (!match_window( win, msg->win )) continue;
805
        if (!check_msg_filter( msg->msg, first, last )) continue;
806
        goto found; /* found one */
807
    }
808
    return 0;
809 810

    /* return it to the app */
811
found:
812 813 814 815 816 817 818 819 820 821 822
    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;
823 824
    reply->x      = msg->x;
    reply->y      = msg->y;
825 826
    reply->time   = msg->time;

827
    if (flags & PM_REMOVE)
828 829 830 831 832 833 834 835 836 837 838 839 840 841
    {
        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;
}

842 843 844 845 846 847 848
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;
849
        reply->win    = 0;
850 851 852
        reply->msg    = WM_QUIT;
        reply->wparam = queue->exit_code;
        reply->lparam = 0;
853 854

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

856
        if (flags & PM_REMOVE)
857
        {
858
            queue->quit_message = 0;
859 860 861
            if (list_empty( &queue->msg_list[POST_MESSAGE] ))
                clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
        }
862 863 864 865 866 867
        return 1;
    }
    else
        return 0;
}

868
/* empty a message list and free all the messages */
869
static void empty_msg_list( struct list *list )
870
{
871 872 873
    struct list *ptr;

    while ((ptr = list_head( list )) != NULL)
874
    {
875 876
        struct message *msg = LIST_ENTRY( ptr, struct message, entry );
        list_remove( &msg->entry );
877 878 879 880 881 882 883
        free_message( msg );
    }
}

/* cleanup all pending results when deleting a queue */
static void cleanup_results( struct msg_queue *queue )
{
884 885 886 887 888 889
    struct list *entry;

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

891
    while ((entry = list_head( &queue->callback_result )) != NULL)
892
    {
893
        remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
894 895
    }

896 897
    while (queue->recv_result)
        reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
898 899
}

900 901 902 903 904
/* 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;

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

908
    LIST_FOR_EACH_ENTRY( entry, &queue->obj.wait_queue, struct wait_queue_entry, entry )
909
    {
910
        if (get_wait_queue_thread(entry)->queue == queue)
911 912 913 914 915
            return 0;  /* thread is waiting on queue -> not hung */
    }
    return 1;
}

916 917 918
static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
{
    struct msg_queue *queue = (struct msg_queue *)obj;
919
    struct process *process = get_wait_queue_thread(entry)->process;
920

921
    /* a thread can only wait on its own queue */
922
    if (get_wait_queue_thread(entry)->queue != queue)
923 924 925 926
    {
        set_error( STATUS_ACCESS_DENIED );
        return 0;
    }
927
    if (process->idle_event && !(queue->wake_mask & QS_SMRESULT)) set_event( process->idle_event );
928

929 930
    if (queue->fd && list_empty( &obj->wait_queue ))  /* first on the queue */
        set_fd_events( queue->fd, POLLIN );
931 932 933 934 935 936 937 938 939
    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 );
940 941
    if (queue->fd && list_empty( &obj->wait_queue ))  /* last on the queue is gone */
        set_fd_events( queue->fd, 0 );
942 943 944 945 946
}

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

951
static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry )
952 953
{
    struct msg_queue *queue = (struct msg_queue *)obj;
954 955 956 957 958 959 960 961 962 963 964 965
    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 );
966 967
}

968
static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry )
969 970
{
    struct msg_queue *queue = (struct msg_queue *)obj;
971 972
    queue->wake_mask = 0;
    queue->changed_mask = 0;
973 974
}

975 976 977
static void msg_queue_destroy( struct object *obj )
{
    struct msg_queue *queue = (struct msg_queue *)obj;
978
    struct list *ptr;
979
    struct hotkey *hotkey, *hotkey2;
980
    int i;
981 982

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

985 986 987 988 989 990 991 992 993
    LIST_FOR_EACH_ENTRY_SAFE( hotkey, hotkey2, &queue->input->desktop->hotkeys, struct hotkey, entry )
    {
        if (hotkey->queue == queue)
        {
            list_remove( &hotkey->entry );
            free( hotkey );
        }
    }

994
    while ((ptr = list_head( &queue->pending_timers )))
995
    {
996 997 998 999 1000 1001 1002 1003
        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 );
1004 1005 1006
        free( timer );
    }
    if (queue->timeout) remove_timeout_user( queue->timeout );
1007 1008
    queue->input->cursor_count -= queue->cursor_count;
    release_object( queue->input );
1009
    if (queue->hooks) release_object( queue->hooks );
1010 1011 1012 1013 1014 1015 1016 1017 1018
    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 );
1019
    else set_fd_events( queue->fd, 0 );
1020
    wake_up( &queue->obj, 0 );
1021 1022 1023 1024 1025
}

static void thread_input_dump( struct object *obj, int verbose )
{
    struct thread_input *input = (struct thread_input *)obj;
1026
    fprintf( stderr, "Thread input focus=%08x capture=%08x active=%08x\n",
1027 1028 1029 1030 1031 1032 1033
             input->focus, input->capture, input->active );
}

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

1034
    empty_msg_list( &input->msg_list );
1035 1036
    if (input->desktop)
    {
1037
        if (input->desktop->foreground_input == input) set_foreground_input( input->desktop, NULL );
1038 1039
        release_object( input->desktop );
    }
1040 1041 1042
}

/* fix the thread input data when a window is destroyed */
1043
static inline void thread_input_cleanup_window( struct msg_queue *queue, user_handle_t window )
1044 1045 1046 1047 1048 1049 1050 1051
{
    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;
1052
    if (window == input->caret) set_caret_window( input, 0 );
1053 1054
}

1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
/* 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;
}

1074 1075 1076 1077 1078 1079 1080
/* 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);
}

1081 1082 1083
/* attach two thread input data structures */
int attach_thread_input( struct thread *thread_from, struct thread *thread_to )
{
1084
    struct desktop *desktop;
1085
    struct thread_input *input;
1086
    int ret;
1087 1088

    if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0;
1089
    if (!(desktop = get_thread_desktop( thread_from, 0 ))) return 0;
1090
    input = (struct thread_input *)grab_object( thread_to->queue->input );
1091 1092 1093 1094 1095 1096 1097 1098
    if (input->desktop != desktop)
    {
        set_error( STATUS_ACCESS_DENIED );
        release_object( input );
        release_object( desktop );
        return 0;
    }
    release_object( desktop );
1099

1100 1101 1102 1103 1104 1105
    if (thread_from->queue)
    {
        if (!input->focus) input->focus = thread_from->queue->input->focus;
        if (!input->active) input->active = thread_from->queue->input->active;
    }

1106 1107 1108 1109
    ret = assign_thread_input( thread_from, input );
    if (ret) memset( input->keystate, 0, sizeof(input->keystate) );
    release_object( input );
    return ret;
1110 1111
}

1112
/* detach two thread input data structures */
1113
void detach_thread_input( struct thread *thread_from )
1114
{
1115 1116
    struct thread *thread;
    struct thread_input *input, *old_input = thread_from->queue->input;
1117

1118
    if ((input = create_thread_input( thread_from )))
1119
    {
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
        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 );
        }
1138 1139
        assign_thread_input( thread_from, input );
        release_object( input );
1140 1141 1142 1143
    }
}


1144
/* set the next timer to expire */
1145
static void set_next_timer( struct msg_queue *queue )
1146
{
1147 1148
    struct list *ptr;

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

1166 1167
/* find a timer from its window and id */
static struct timer *find_timer( struct msg_queue *queue, user_handle_t win,
1168
                                 unsigned int msg, lparam_t id )
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
{
    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;
}

1187 1188 1189 1190
/* callback for the next timer expiration */
static void timer_callback( void *private )
{
    struct msg_queue *queue = private;
1191
    struct list *ptr;
1192 1193 1194

    queue->timeout = NULL;
    /* move on to the next timer */
1195 1196 1197 1198
    ptr = list_head( &queue->pending_timers );
    list_remove( ptr );
    list_add_tail( &queue->expired_timers, ptr );
    set_next_timer( queue );
1199 1200 1201 1202 1203
}

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

1206
    for (ptr = queue->pending_timers.next; ptr != &queue->pending_timers; ptr = ptr->next)
1207
    {
1208
        struct timer *t = LIST_ENTRY( ptr, struct timer, entry );
1209
        if (t->when >= timer->when) break;
1210
    }
1211
    list_add_before( ptr, &timer->entry );
1212 1213
}

1214 1215
/* remove a timer from the queue timer list and free it */
static void free_timer( struct msg_queue *queue, struct timer *timer )
1216
{
1217 1218 1219
    list_remove( &timer->entry );
    free( timer );
    set_next_timer( queue );
1220 1221 1222 1223 1224
}

/* restart an expired timer */
static void restart_timer( struct msg_queue *queue, struct timer *timer )
{
1225
    list_remove( &timer->entry );
1226
    while (timer->when <= current_time) timer->when += (timeout_t)timer->rate * 10000;
1227
    link_timer( queue, timer );
1228
    set_next_timer( queue );
1229 1230 1231
}

/* find an expired timer matching the filtering parameters */
1232
static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t win,
1233 1234 1235
                                         unsigned int get_first, unsigned int get_last,
                                         int remove )
{
1236 1237 1238
    struct list *ptr;

    LIST_FOR_EACH( ptr, &queue->expired_timers )
1239
    {
1240
        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
1241
        if (win && timer->win != win) continue;
1242
        if (check_msg_filter( timer->msg, get_first, get_last ))
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
        {
            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)
    {
1257
        timer->rate = max( rate, 1 );
1258
        timer->when = current_time + (timeout_t)timer->rate * 10000;
1259
        link_timer( queue, timer );
1260 1261
        /* check if we replaced the next timer */
        if (list_head( &queue->pending_timers ) == &timer->entry) set_next_timer( queue );
1262 1263 1264 1265
    }
    return timer;
}

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

/* update the input key state for a keyboard message */
1278 1279
static void update_input_key_state( struct desktop *desktop, unsigned char *keystate,
                                    const struct message *msg )
1280 1281
{
    unsigned char key;
1282
    int down = 0;
1283 1284 1285 1286

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

1341
/* release the hardware message currently being processed by the given thread */
1342
static void release_hardware_message( struct msg_queue *queue, unsigned int hw_id,
1343
                                      int remove )
1344
{
1345 1346
    struct thread_input *input = queue->input;
    struct message *msg;
1347

1348 1349 1350 1351 1352
    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 */
1353 1354

    /* clear the queue bit for that message */
1355
    if (remove)
1356 1357 1358 1359
    {
        struct message *other;
        int clr_bit;

1360
        clr_bit = get_hardware_msg_bit( msg );
1361 1362
        LIST_FOR_EACH_ENTRY( other, &input->msg_list, struct message, entry )
        {
1363
            if (other != msg && get_hardware_msg_bit( other ) == clr_bit)
1364 1365 1366 1367 1368
            {
                clr_bit = 0;
                break;
            }
        }
1369
        if (clr_bit) clear_queue_bits( queue, clr_bit );
1370

1371
        update_input_key_state( input->desktop, input->keystate, msg );
1372 1373
        list_remove( &msg->entry );
        free_message( msg );
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 1404 1405 1406 1407 1408
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 );
1409 1410
    set_queue_bits( hotkey->queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE|QS_HOTKEY );
    hotkey->queue->hotkey_count++;
1411 1412 1413
    return 1;
}

1414
/* find the window that should receive a given hardware message */
1415
static user_handle_t find_hardware_message_window( struct desktop *desktop, struct thread_input *input,
1416 1417
                                                   struct message *msg, unsigned int *msg_code,
                                                   struct thread **thread )
1418 1419 1420
{
    user_handle_t win = 0;

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

1440
        *thread = window_thread_from_point( win, msg->x, msg->y );
1441
    }
1442 1443 1444

    if (!*thread)
        *thread = get_window_thread( win );
1445 1446 1447
    return win;
}

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 1477 1478 1479 1480 1481
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 );
}

1482
/* queue a hardware message into a given thread input */
1483
static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue )
1484 1485
{
    user_handle_t win;
1486
    struct thread *thread;
1487
    struct thread_input *input;
1488
    unsigned int msg_code;
1489

1490
    update_input_key_state( desktop, desktop->keystate, msg );
1491
    last_input_time = get_tick_count();
1492
    if (msg->msg != WM_MOUSEMOVE) always_queue = 1;
1493

1494 1495
    if (is_keyboard_msg( msg ))
    {
1496
        if (queue_hotkey_message( desktop, msg )) return;
1497 1498 1499 1500
        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);
    }
1501
    else if (msg->msg != WM_INPUT)
1502
    {
1503 1504
        if (msg->msg == WM_MOUSEMOVE)
        {
1505 1506
            int x = max( min( msg->x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left );
            int y = max( min( msg->y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top );
1507 1508 1509
            if (desktop->cursor.x != x || desktop->cursor.y != y) always_queue = 1;
            desktop->cursor.x = x;
            desktop->cursor.y = y;
1510 1511
            desktop->cursor.last_change = get_tick_count();
        }
1512 1513 1514 1515 1516 1517 1518 1519
        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;
    }
1520 1521
    msg->x = desktop->cursor.x;
    msg->y = desktop->cursor.y;
1522

1523 1524 1525 1526 1527 1528 1529
    if (msg->win && (thread = get_window_thread( msg->win )))
    {
        input = thread->queue->input;
        release_object( thread );
    }
    else input = desktop->foreground_input;

1530 1531
    win = find_hardware_message_window( desktop, input, msg, &msg_code, &thread );
    if (!win || !thread)
1532
    {
1533
        if (input) update_input_key_state( input->desktop, input->keystate, msg );
1534
        free_message( msg );
1535 1536
        return;
    }
1537
    input = thread->queue->input;
1538

1539 1540 1541 1542
    if (win != desktop->cursor.win) always_queue = 1;
    desktop->cursor.win = win;

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

1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
/* 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;
1564
    if (is_queue_hung( queue )) return 0;
1565 1566 1567 1568 1569 1570 1571

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

    msg->type      = MSG_HOOK_LL;
    msg->win       = 0;
    msg->msg       = id;
    msg->wparam    = hardware_msg->msg;
1572 1573
    msg->x         = hardware_msg->x;
    msg->y         = hardware_msg->y;
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583
    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;
    }
1584
    else msg->lparam = input->mouse.data << 16;
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598

    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;
}

1599
/* queue a hardware message for a mouse event */
1600
static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
1601
                                unsigned int origin, struct msg_queue *sender )
1602
{
1603
    const struct rawinput_device *device;
1604 1605
    struct hardware_msg_data *msg_data;
    struct message *msg;
1606
    unsigned int i, time, flags;
1607
    struct hw_msg_source source = { IMDT_MOUSE, origin };
1608
    int wait = 0, x, y;
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626

    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 */
    };

1627
    desktop->cursor.last_change = get_tick_count();
1628 1629
    flags = input->mouse.flags;
    time  = input->mouse.time;
1630
    if (!time) time = desktop->cursor.last_change;
1631 1632 1633 1634 1635 1636 1637 1638

    if (flags & MOUSEEVENTF_MOVE)
    {
        if (flags & MOUSEEVENTF_ABSOLUTE)
        {
            x = input->mouse.x;
            y = input->mouse.y;
            if (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE) &&
1639
                x == desktop->cursor.x && y == desktop->cursor.y)
1640 1641 1642 1643
                flags &= ~MOUSEEVENTF_MOVE;
        }
        else
        {
1644 1645
            x = desktop->cursor.x + input->mouse.x;
            y = desktop->cursor.y + input->mouse.y;
1646 1647 1648
        }
    }
    else
1649
    {
1650 1651
        x = desktop->cursor.x;
        y = desktop->cursor.y;
1652 1653
    }

1654 1655
    if ((device = current->process->rawinput_mouse))
    {
1656
        if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0;
1657
        msg_data = msg->data;
1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672

        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 );
    }

1673
    for (i = 0; i < ARRAY_SIZE( messages ); i++)
1674 1675 1676
    {
        if (!messages[i]) continue;
        if (!(flags & (1 << i))) continue;
1677
        flags &= ~(1 << i);
1678

1679
        if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0;
1680
        msg_data = msg->data;
1681 1682 1683 1684 1685

        msg->win       = get_user_full_handle( win );
        msg->msg       = messages[i];
        msg->wparam    = input->mouse.data << 16;
        msg->lparam    = 0;
1686 1687
        msg->x         = x;
        msg->y         = y;
1688
        if (origin == IMO_INJECTED) msg_data->flags = LLMHF_INJECTED;
1689

1690
        /* specify a sender only when sending the last message */
1691
        if (!(flags & ((1 << ARRAY_SIZE( messages )) - 1)))
1692 1693
        {
            if (!(wait = send_hook_ll_message( desktop, msg, input, sender )))
1694
                queue_hardware_message( desktop, msg, 0 );
1695 1696
        }
        else if (!send_hook_ll_message( desktop, msg, input, NULL ))
1697
            queue_hardware_message( desktop, msg, 0 );
1698
    }
1699
    return wait;
1700 1701 1702
}

/* queue a hardware message for a keyboard event */
1703
static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
1704
                                   unsigned int origin, struct msg_queue *sender )
1705
{
1706
    struct hw_msg_source source = { IMDT_KEYBOARD, origin };
1707
    const struct rawinput_device *device;
1708 1709 1710
    struct hardware_msg_data *msg_data;
    struct message *msg;
    unsigned char vkey = input->kbd.vkey;
1711
    unsigned int message_code, time;
1712
    int wait;
1713

1714
    if (!(time = input->kbd.time)) time = get_tick_count();
1715

1716
    if (!(input->kbd.flags & KEYEVENTF_UNICODE))
1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737
    {
        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;
        }
    }

1738
    message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_KEYUP : WM_KEYDOWN;
1739 1740 1741 1742 1743 1744 1745 1746 1747
    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;
1748
            message_code = WM_SYSKEYUP;
1749 1750 1751 1752 1753 1754
            desktop->keystate[VK_MENU] &= ~0x02;
        }
        else
        {
            /* send WM_SYSKEYDOWN for Alt except with Ctrl */
            if (desktop->keystate[VK_CONTROL] & 0x80) break;
1755
            message_code = WM_SYSKEYDOWN;
1756 1757 1758 1759 1760 1761 1762 1763 1764
            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;
1765
        message_code = WM_SYSKEYUP;
1766 1767 1768 1769 1770 1771 1772 1773 1774
        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:
1775
        message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_SYSKEYUP : WM_SYSKEYDOWN;
1776 1777 1778
        desktop->keystate[VK_MENU] &= ~0x02;
        break;
    }
1779 1780 1781

    if ((device = current->process->rawinput_kbd))
    {
1782 1783 1784
        if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0;
        msg_data = msg->data;

1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797
        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 );
    }

1798 1799 1800
    if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0;
    msg_data = msg->data;

1801 1802 1803
    msg->win       = get_user_full_handle( win );
    msg->msg       = message_code;
    msg->lparam    = (input->kbd.scan << 16) | 1u; /* repeat count */
1804
    if (origin == IMO_INJECTED) msg_data->flags = LLKHF_INJECTED;
1805

1806
    if (input->kbd.flags & KEYEVENTF_UNICODE && !vkey)
1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822
    {
        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;
    }

1823
    if (!(wait = send_hook_ll_message( desktop, msg, input, sender )))
1824
        queue_hardware_message( desktop, msg, 1 );
1825

1826
    return wait;
1827 1828 1829 1830
}

/* queue a hardware message for a custom type of event */
static void queue_custom_hardware_message( struct desktop *desktop, user_handle_t win,
1831
                                           unsigned int origin, const hw_input_t *input )
1832
{
1833
    struct hw_msg_source source = { IMDT_UNAVAILABLE, origin };
1834 1835
    struct message *msg;

1836
    if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return;
1837 1838 1839 1840 1841

    msg->win       = get_user_full_handle( win );
    msg->msg       = input->hw.msg;
    msg->wparam    = 0;
    msg->lparam    = input->hw.lparam;
1842 1843
    msg->x         = desktop->cursor.x;
    msg->y         = desktop->cursor.y;
1844

1845
    queue_hardware_message( desktop, msg, 1 );
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 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
/* 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;
    }
}


1883
/* find a hardware message for the given queue */
1884
static int get_hardware_message( struct thread *thread, unsigned int hw_id, user_handle_t filter_win,
1885 1886
                                 unsigned int first, unsigned int last, unsigned int flags,
                                 struct get_message_reply *reply )
1887 1888 1889
{
    struct thread_input *input = thread->queue->input;
    struct thread *win_thread;
1890
    struct list *ptr;
1891 1892
    user_handle_t win;
    int clear_bits, got_one = 0;
1893
    unsigned int msg_code;
1894

1895 1896
    ptr = list_head( &input->msg_list );
    if (hw_id)
1897
    {
1898 1899 1900 1901 1902 1903 1904 1905
        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 */
1906
    }
1907 1908

    if (ptr == list_head( &input->msg_list ))
1909
        clear_bits = QS_INPUT;
1910 1911 1912
    else
        clear_bits = 0;  /* don't clear bits if we don't go through the whole list */

1913
    while (ptr)
1914
    {
1915
        struct message *msg = LIST_ENTRY( ptr, struct message, entry );
1916 1917
        struct hardware_msg_data *data = msg->data;

1918
        ptr = list_next( &input->msg_list, ptr );
1919 1920
        win = find_hardware_message_window( input->desktop, input, msg, &msg_code, &win_thread );
        if (!win || !win_thread)
1921 1922
        {
            /* no window at all, remove it */
1923
            update_input_key_state( input->desktop, input->keystate, msg );
1924
            list_remove( &msg->entry );
1925 1926 1927 1928 1929
            free_message( msg );
            continue;
        }
        if (win_thread != thread)
        {
1930 1931 1932 1933 1934 1935 1936 1937 1938
            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 */
1939
                update_input_key_state( input->desktop, input->keystate, msg );
1940 1941 1942
                list_remove( &msg->entry );
                free_message( msg );
            }
1943 1944 1945
            release_object( win_thread );
            continue;
        }
1946 1947
        release_object( win_thread );

1948
        /* if we already got a message for another thread, or if it doesn't
1949 1950
         * match the filter we skip it */
        if (got_one || !check_hw_message_filter( win, msg_code, filter_win, first, last ))
1951 1952 1953 1954 1955
        {
            clear_bits &= ~get_hardware_msg_bit( msg );
            continue;
        }
        /* now we can return it */
1956
        if (!msg->unique_id) msg->unique_id = get_unique_id();
1957 1958
        reply->type   = MSG_HARDWARE;
        reply->win    = win;
1959
        reply->msg    = msg_code;
1960 1961
        reply->wparam = msg->wparam;
        reply->lparam = msg->lparam;
1962 1963
        reply->x      = msg->x;
        reply->y      = msg->y;
1964
        reply->time   = msg->time;
1965 1966 1967

        data->hw_id = msg->unique_id;
        set_reply_data( msg->data, msg->data_size );
1968
        if (msg->msg == WM_INPUT && (flags & PM_REMOVE))
1969
            release_hardware_message( current->queue, data->hw_id, 1 );
1970 1971 1972 1973 1974 1975
        return 1;
    }
    /* nothing found, clear the hardware queue bits */
    clear_queue_bits( thread->queue, clear_bits );
    return 0;
}
1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992

/* 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 );
}


1993
/* remove all messages and timers belonging to a certain window */
1994
void queue_cleanup_window( struct thread *thread, user_handle_t win )
1995
{
1996
    struct msg_queue *queue = thread->queue;
1997
    struct list *ptr;
1998
    int i;
1999

2000 2001
    if (!queue) return;

2002
    /* remove timers */
2003 2004 2005

    ptr = list_head( &queue->pending_timers );
    while (ptr)
2006
    {
2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018
        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;
2019 2020
    }

2021 2022
    /* remove messages */
    for (i = 0; i < NB_MSG_KINDS; i++)
2023
    {
2024 2025 2026
        struct list *ptr, *next;

        LIST_FOR_EACH_SAFE( ptr, next, &queue->msg_list[i] )
2027
        {
2028
            struct message *msg = LIST_ENTRY( ptr, struct message, entry );
2029 2030 2031 2032 2033 2034 2035 2036 2037
            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 );
            }
2038
        }
2039
    }
2040 2041

    thread_input_cleanup_window( queue, win );
2042 2043
}

2044
/* post a message to a window */
2045
void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam )
2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062
{
    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;

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

2065
        list_add_tail( &thread->queue->msg_list[POST_MESSAGE], &msg->entry );
2066
        set_queue_bits( thread->queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE );
2067 2068 2069 2070 2071
        if (message == WM_HOTKEY)
        {
            set_queue_bits( thread->queue, QS_HOTKEY );
            thread->queue->hotkey_count++;
        }
2072 2073 2074 2075
    }
    release_object( thread );
}

2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102
/* 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 );
}

2103 2104 2105
/* post a win event */
void post_win_event( struct thread *thread, unsigned int event,
                     user_handle_t win, unsigned int object_id,
2106
                     unsigned int child_id, client_ptr_t hook_proc,
2107
                     const WCHAR *module, data_size_t module_size,
2108 2109 2110 2111 2112 2113
                     user_handle_t hook)
{
    struct message *msg;

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

2116 2117 2118 2119 2120 2121 2122 2123
        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;

2124
        if ((data = malloc( sizeof(*data) + module_size )))
2125
        {
2126 2127 2128 2129 2130 2131 2132
            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;
2133 2134

            if (debug_level > 1)
2135
                fprintf( stderr, "post_win_event: tid %04x event %04x win %08x object_id %d child_id %d\n",
2136
                         get_thread_id(thread), event, win, object_id, child_id );
2137
            list_add_tail( &thread->queue->msg_list[SEND_MESSAGE], &msg->entry );
2138 2139 2140 2141 2142 2143
            set_queue_bits( thread->queue, QS_SENDMESSAGE );
        }
        else
            free( msg );
    }
}
2144

2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159
/* 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 );
        }
    }
}

2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175

/* 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;
}


2176 2177 2178
/* get the message queue of the current thread */
DECL_HANDLER(get_msg_queue)
{
2179
    struct msg_queue *queue = get_current_queue();
2180

2181 2182
    reply->handle = 0;
    if (queue) reply->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
2183 2184
}

2185

2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202
/* 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)
2203
            queue->fd = create_anonymous_fd( &msg_queue_fd_ops, unix_fd, &queue->obj, 0 );
2204 2205 2206 2207 2208 2209 2210
        else
            file_set_error();
    }
    release_object( file );
}


2211 2212 2213 2214 2215 2216 2217 2218 2219
/* 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;
2220 2221
        reply->wake_bits    = queue->wake_bits;
        reply->changed_bits = queue->changed_bits;
2222 2223 2224
        if (is_signaled( queue ))
        {
            /* if skip wait is set, do what would have been done in the subsequent wait */
2225
            if (req->skip_wait) queue->wake_mask = queue->changed_mask = 0;
2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237
            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)
    {
2238 2239
        reply->wake_bits    = queue->wake_bits;
        reply->changed_bits = queue->changed_bits;
2240
        queue->changed_bits &= ~req->clear_bits;
2241
    }
2242
    else reply->wake_bits = reply->changed_bits = 0;
2243 2244 2245 2246 2247 2248 2249 2250
}


/* send a message to a thread queue */
DECL_HANDLER(send_message)
{
    struct message *msg;
    struct msg_queue *send_queue = get_current_queue();
2251 2252
    struct msg_queue *recv_queue = NULL;
    struct thread *thread = NULL;
2253

2254
    if (!(thread = get_thread_from_id( req->id ))) return;
2255

2256
    if (!(recv_queue = thread->queue))
2257 2258 2259 2260 2261
    {
        set_error( STATUS_INVALID_PARAMETER );
        release_object( thread );
        return;
    }
2262
    if ((req->flags & SEND_MSG_ABORT_IF_HUNG) && is_queue_hung(recv_queue))
2263 2264 2265 2266 2267
    {
        set_error( STATUS_TIMEOUT );
        release_object( thread );
        return;
    }
2268 2269 2270

    if ((msg = mem_alloc( sizeof(*msg) )))
    {
2271
        msg->type      = req->type;
2272
        msg->win       = get_user_full_handle( req->win );
2273 2274 2275 2276 2277
        msg->msg       = req->msg;
        msg->wparam    = req->wparam;
        msg->lparam    = req->lparam;
        msg->result    = NULL;
        msg->data      = NULL;
2278 2279
        msg->data_size = get_req_data_size();

2280 2281
        get_message_defaults( recv_queue, &msg->x, &msg->y, &msg->time );

2282 2283 2284 2285 2286 2287
        if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size )))
        {
            free( msg );
            release_object( thread );
            return;
        }
2288 2289

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

/* send a hardware message to a thread queue */
DECL_HANDLER(send_hardware_message)
{
    struct thread *thread = NULL;
2330
    struct desktop *desktop;
2331
    unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE);
2332
    struct msg_queue *sender = get_current_queue();
2333 2334 2335
    data_size_t size = min( 256, get_reply_max_size() );

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

2337
    if (req->win)
2338
    {
2339
        if (!(thread = get_window_thread( req->win ))) return;
2340 2341 2342 2343 2344 2345
        if (desktop != thread->queue->input->desktop)
        {
            /* don't allow queuing events to a different desktop */
            release_object( desktop );
            return;
        }
2346
    }
2347

2348 2349 2350
    reply->prev_x = desktop->cursor.x;
    reply->prev_y = desktop->cursor.y;

2351
    switch (req->input.type)
2352
    {
2353
    case INPUT_MOUSE:
2354
        reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender );
2355 2356
        break;
    case INPUT_KEYBOARD:
2357
        reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender );
2358 2359
        break;
    case INPUT_HARDWARE:
2360
        queue_custom_hardware_message( desktop, req->win, origin, &req->input );
2361 2362 2363
        break;
    default:
        set_error( STATUS_INVALID_PARAMETER );
2364
    }
2365
    if (thread) release_object( thread );
2366 2367 2368

    reply->new_x = desktop->cursor.x;
    reply->new_y = desktop->cursor.y;
2369
    set_reply_data( desktop->keystate, size );
2370
    release_object( desktop );
2371 2372
}

2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384
/* 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 );
}
2385

2386 2387 2388 2389
/* get a message from the current queue */
DECL_HANDLER(get_message)
{
    struct timer *timer;
2390
    struct list *ptr;
2391
    struct msg_queue *queue = get_current_queue();
2392
    user_handle_t get_win = get_user_full_handle( req->get_win );
2393
    unsigned int filter = req->flags >> 16;
2394

2395 2396
    reply->active_hooks = get_active_hooks();

2397 2398 2399 2400 2401 2402
    if (get_win && get_win != 1 && get_win != -1 && !get_user_object( get_win, USER_WINDOW ))
    {
        set_win32_error( ERROR_INVALID_WINDOW_HANDLE );
        return;
    }

2403
    if (!queue) return;
2404
    queue->last_get_msg = current_time;
2405
    if (!filter) filter = QS_ALLINPUT;
2406 2407

    /* first check for sent messages */
2408
    if ((ptr = list_head( &queue->msg_list[SEND_MESSAGE] )))
2409
    {
2410
        struct message *msg = LIST_ENTRY( ptr, struct message, entry );
2411
        receive_message( queue, msg, reply );
2412 2413 2414
        return;
    }

2415
    /* clear changed bits so we can wait on them if we don't find a message */
2416 2417 2418 2419 2420 2421 2422
    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;
2423

2424
    /* then check for posted messages */
2425 2426
    if ((filter & QS_POSTMESSAGE) &&
        get_posted_message( queue, get_win, req->get_first, req->get_last, req->flags, reply ))
2427 2428
        return;

2429 2430 2431 2432 2433
    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;

2434 2435
    /* only check for quit messages if not posted messages pending */
    if ((filter & QS_POSTMESSAGE) && get_quit_message( queue, req->flags, reply ))
2436 2437
        return;

2438
    /* then check for any raw hardware message */
2439 2440
    if ((filter & QS_INPUT) &&
        filter_contains_hw_range( req->get_first, req->get_last ) &&
2441
        get_hardware_message( current, req->hw_id, get_win, req->get_first, req->get_last, req->flags, reply ))
2442
        return;
2443 2444

    /* now check for WM_PAINT */
2445 2446
    if ((filter & QS_PAINT) &&
        queue->paint_count &&
2447
        check_msg_filter( WM_PAINT, req->get_first, req->get_last ) &&
2448 2449 2450 2451 2452 2453
        (reply->win = find_window_to_repaint( get_win, current )))
    {
        reply->type   = MSG_POSTED;
        reply->msg    = WM_PAINT;
        reply->wparam = 0;
        reply->lparam = 0;
2454
        get_message_defaults( queue, &reply->x, &reply->y, &reply->time );
2455 2456 2457 2458
        return;
    }

    /* now check for timer */
2459 2460 2461
    if ((filter & QS_TIMER) &&
        (timer = find_expired_timer( queue, get_win, req->get_first,
                                     req->get_last, (req->flags & PM_REMOVE) )))
2462
    {
2463 2464 2465 2466 2467
        reply->type   = MSG_POSTED;
        reply->win    = timer->win;
        reply->msg    = timer->msg;
        reply->wparam = timer->id;
        reply->lparam = timer->lparam;
2468
        get_message_defaults( queue, &reply->x, &reply->y, &reply->time );
2469 2470
        if (!(req->flags & PM_NOYIELD) && current->process->idle_event)
            set_event( current->process->idle_event );
2471 2472 2473
        return;
    }

2474
    if (get_win == -1 && current->process->idle_event) set_event( current->process->idle_event );
2475 2476
    queue->wake_mask = req->wake_mask;
    queue->changed_mask = req->changed_mask;
2477 2478 2479 2480 2481 2482 2483
    set_error( STATUS_PENDING );  /* FIXME */
}


/* reply to a sent message */
DECL_HANDLER(reply_message)
{
2484
    if (!current->queue) set_error( STATUS_ACCESS_DENIED );
2485 2486 2487
    else if (current->queue->recv_result)
        reply_message( current->queue, req->result, 0, req->remove,
                       get_req_data(), get_req_data_size() );
2488 2489 2490
}


2491 2492 2493 2494
/* accept the current hardware message */
DECL_HANDLER(accept_hardware_message)
{
    if (current->queue)
2495
        release_hardware_message( current->queue, req->hw_id, req->remove );
2496 2497
    else
        set_error( STATUS_ACCESS_DENIED );
2498 2499 2500
}


2501 2502 2503
/* retrieve the reply for the last message sent */
DECL_HANDLER(get_message_reply)
{
2504 2505
    struct message_result *result;
    struct list *entry;
2506
    struct msg_queue *queue = current->queue;
2507

2508 2509 2510
    if (queue)
    {
        set_error( STATUS_PENDING );
2511
        reply->result = 0;
2512

2513 2514 2515 2516
        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)
2517
        {
2518 2519
            if (result->replied)
            {
2520
                reply->result = result->result;
2521 2522 2523
                set_error( result->error );
                if (result->data)
                {
2524
                    data_size_t data_len = min( result->data_size, get_reply_max_size() );
2525
                    set_reply_data_ptr( result->data, data_len );
2526 2527 2528 2529
                    result->data = NULL;
                    result->data_size = 0;
                }
            }
2530 2531 2532 2533 2534 2535 2536
            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 );
2537 2538
                if (result->replied) set_queue_bits( queue, QS_SMRESULT );
                else clear_queue_bits( queue, QS_SMRESULT );
2539
            }
2540 2541
        }
    }
2542
    else set_error( STATUS_ACCESS_DENIED );
2543 2544 2545 2546 2547 2548 2549
}


/* set a window timer */
DECL_HANDLER(set_win_timer)
{
    struct timer *timer;
2550 2551 2552
    struct msg_queue *queue;
    struct thread *thread = NULL;
    user_handle_t win = 0;
2553
    lparam_t id = req->id;
2554

2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574
    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();
2575
        /* look for a timer with this id */
2576
        if (id && (timer = find_timer( queue, 0, req->msg, id )))
2577
        {
2578 2579 2580 2581 2582
            /* free and reuse id */
            free_timer( queue, timer );
        }
        else
        {
2583 2584
            lparam_t end_id = queue->next_timer_id;

2585
            /* find a free id for it */
2586
            while (1)
2587 2588
            {
                id = queue->next_timer_id;
2589
                if (--queue->next_timer_id <= 0x100) queue->next_timer_id = 0x7fff;
2590 2591 2592 2593 2594 2595 2596

                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;
                }
2597
            }
2598 2599
        }
    }
2600 2601 2602

    if ((timer = set_timer( queue, req->rate )))
    {
2603
        timer->win    = win;
2604
        timer->msg    = req->msg;
2605
        timer->id     = id;
2606
        timer->lparam = req->lparam;
2607
        reply->id     = id;
2608
    }
2609
    if (thread) release_object( thread );
2610 2611 2612 2613 2614
}

/* kill a window timer */
DECL_HANDLER(kill_win_timer)
{
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633
    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 );
2634

2635 2636 2637
    if (thread->queue && (timer = find_timer( thread->queue, win, req->msg, req->id )))
        free_timer( thread->queue, timer );
    else
2638
        set_error( STATUS_INVALID_PARAMETER );
2639 2640

    release_object( thread );
2641
}
2642

2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655
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)
    {
2656
        if (!(win_handle = get_valid_window_handle( win_handle )))
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 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723
        {
            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)
    {
2724
        if (!(win_handle = get_valid_window_handle( win_handle )))
2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757
        {
            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 );
}
2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772

/* 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)
    {
2773 2774 2775 2776 2777 2778 2779 2780
        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 );
        }
2781 2782 2783 2784 2785 2786 2787 2788
        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 );
        }
2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799
    }
    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;
2800
    struct desktop *desktop;
2801 2802 2803 2804 2805
    struct thread_input *input;

    if (req->tid)
    {
        if (!(thread = get_thread_from_id( req->tid ))) return;
2806 2807 2808 2809 2810
        if (!(desktop = get_thread_desktop( thread, 0 )))
        {
            release_object( thread );
            return;
        }
2811 2812
        input = thread->queue ? thread->queue->input : NULL;
    }
2813 2814 2815 2816 2817
    else
    {
        if (!(desktop = get_thread_desktop( current, 0 ))) return;
        input = desktop->foreground_input;  /* get the foreground thread info */
    }
2818 2819 2820 2821 2822 2823 2824 2825 2826

    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;
2827 2828
        reply->cursor     = input->cursor;
        reply->show_count = input->cursor_count;
2829
        reply->rect       = input->caret_rect;
2830
    }
2831

2832
    /* foreground window is active window of foreground thread */
2833
    reply->foreground = desktop->foreground_input ? desktop->foreground_input->active : 0;
2834
    if (thread) release_object( thread );
2835
    release_object( desktop );
2836
}
2837 2838


2839 2840 2841 2842
/* retrieve queue keyboard state for a given thread */
DECL_HANDLER(get_key_state)
{
    struct thread *thread;
2843 2844
    struct desktop *desktop;
    data_size_t size = min( 256, get_reply_max_size() );
2845

2846
    if (!req->tid)  /* get global async key state */
2847
    {
2848
        if (!(desktop = get_thread_desktop( current, 0 ))) return;
2849 2850 2851 2852 2853
        if (req->key >= 0)
        {
            reply->state = desktop->keystate[req->key & 0xff];
            desktop->keystate[req->key & 0xff] &= ~0x40;
        }
2854 2855 2856 2857 2858
        set_reply_data( desktop->keystate, size );
        release_object( desktop );
    }
    else
    {
2859
        unsigned char *keystate;
2860 2861 2862 2863 2864
        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 );
2865 2866
            release_object( thread );
            return;
2867 2868
        }
        release_object( thread );
2869 2870 2871 2872 2873 2874 2875 2876 2877 2878

        /* 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 );
2879 2880 2881 2882 2883 2884 2885
    }
}


/* set queue keyboard state for a given thread */
DECL_HANDLER(set_key_state)
{
2886 2887 2888
    struct thread *thread;
    struct desktop *desktop;
    data_size_t size = min( 256, get_req_data_size() );
2889

2890
    if (!req->tid)  /* set global async key state */
2891
    {
2892 2893 2894 2895 2896 2897 2898 2899
        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 );
2900 2901 2902 2903 2904
        if (req->async && (desktop = get_thread_desktop( thread, 0 )))
        {
            memcpy( desktop->keystate, get_req_data(), size );
            release_object( desktop );
        }
2905
        release_object( thread );
2906 2907 2908 2909
    }
}


2910 2911 2912
/* set the system foreground window */
DECL_HANDLER(set_foreground_window)
{
2913 2914
    struct thread *thread = NULL;
    struct desktop *desktop;
2915 2916
    struct msg_queue *queue = get_current_queue();

2917 2918 2919
    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);
2920 2921
    reply->send_msg_new = FALSE;

2922 2923 2924
    if (is_valid_foreground_window( req->handle ) &&
        (thread = get_window_thread( req->handle )) &&
        thread->queue->input->desktop == desktop)
2925
    {
2926
        set_foreground_input( desktop, thread->queue->input );
2927
        reply->send_msg_new = (desktop->foreground_input != queue->input);
2928
    }
2929
    else set_win32_error( ERROR_INVALID_WINDOW_HANDLE );
2930 2931 2932

    if (thread) release_object( thread );
    release_object( desktop );
2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965
}


/* 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 );
    }
}
2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977


/* 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;

2978 2979 2980 2981 2982 2983
        /* 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;
        }
2984 2985 2986 2987 2988 2989 2990
        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;
    }
}
2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008


/* 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) );
3009 3010
        input->caret_rect.right  = input->caret_rect.left + req->width;
        input->caret_rect.bottom = input->caret_rect.top + req->height;
3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046
    }
}


/* 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)
    {
3047 3048 3049 3050 3051 3052 3053 3054 3055
        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;
        }
3056 3057
    }
}
3058 3059 3060 3061 3062 3063 3064


/* get the time of the last input event */
DECL_HANDLER(get_last_input_time)
{
    reply->time = last_input_time;
}
3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076

/* 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;
3077 3078
    reply->prev_x      = input->desktop->cursor.x;
    reply->prev_y      = input->desktop->cursor.y;
3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093

    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;
    }
3094 3095
    if (req->flags & SET_CURSOR_POS)
    {
3096 3097
        set_cursor_pos( input->desktop, req->x, req->y );
    }
3098
    if (req->flags & (SET_CURSOR_CLIP | SET_CURSOR_NOCLIP))
3099
    {
3100 3101 3102 3103 3104 3105
        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;

3106
        set_clip_rectangle( desktop, (req->flags & SET_CURSOR_NOCLIP) ? NULL : &req->clip, 0 );
3107 3108
    }

3109 3110 3111 3112
    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;
3113
}
3114 3115 3116 3117 3118

DECL_HANDLER(update_rawinput_devices)
{
    const struct rawinput_device *devices = get_req_data();
    unsigned int device_count = get_req_data_size() / sizeof (*devices);
3119
    const struct rawinput_device_entry *e;
3120 3121 3122 3123 3124 3125
    unsigned int i;

    for (i = 0; i < device_count; ++i)
    {
        update_rawinput_device(&devices[i]);
    }
3126 3127 3128

    e = find_rawinput_device( 1, 2 );
    current->process->rawinput_mouse = e ? &e->device : NULL;
3129 3130
    e = find_rawinput_device( 1, 6 );
    current->process->rawinput_kbd   = e ? &e->device : NULL;
3131
}