1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936 |
- /*
- * Server-side message queues
- *
- * Copyright (C) 2000 Alexandre Julliard
- *
- * 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
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include "config.h"
- #include "wine/port.h"
- #include <assert.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include "windef.h"
- #include "winbase.h"
- #include "wingdi.h"
- #include "winuser.h"
- #include "handle.h"
- #include "file.h"
- #include "thread.h"
- #include "process.h"
- #include "request.h"
- #include "user.h"
- enum message_kind { SEND_MESSAGE, POST_MESSAGE };
- #define NB_MSG_KINDS (POST_MESSAGE+1)
- struct message_result
- {
- struct list sender_entry; /* entry in sender list */
- 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 result; /* reply result */
- unsigned int error; /* error code to pass back to sender */
- 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 */
- };
- struct message
- {
- struct message *next; /* next message in list */
- struct message *prev; /* prev message in list */
- enum message_type type; /* message type */
- user_handle_t win; /* window handle */
- unsigned int msg; /* message code */
- unsigned int wparam; /* parameters */
- unsigned int lparam; /* parameters */
- int x; /* x position */
- int y; /* y position */
- unsigned int time; /* message time */
- unsigned int info; /* extra info */
- user_handle_t hook; /* winevent hook handle */
- void *hook_proc; /* winevent hook proc address */
- void *data; /* message data for sent messages */
- unsigned int data_size; /* size of message data */
- struct message_result *result; /* result in sender queue */
- };
- struct message_list
- {
- struct message *first; /* head of list */
- struct message *last; /* tail of list */
- };
- struct timer
- {
- struct list entry; /* entry in timer list */
- struct timeval when; /* next expiration */
- unsigned int rate; /* timer rate in ms */
- user_handle_t win; /* window handle */
- unsigned int msg; /* message to post */
- unsigned int id; /* timer id */
- unsigned int lparam; /* lparam for message */
- };
- struct thread_input
- {
- struct object obj; /* object header */
- 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 */
- rectangle_t caret_rect; /* caret rectangle */
- int caret_hide; /* caret hide count */
- int caret_state; /* caret on/off state */
- struct message *msg; /* message currently processed */
- struct thread *msg_thread; /* thread processing the message */
- struct message_list msg_list; /* list of hardware messages */
- unsigned char keystate[256]; /* state of each key */
- };
- struct msg_queue
- {
- struct object obj; /* object header */
- 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 */
- struct message_list msg_list[NB_MSG_KINDS]; /* lists of messages */
- 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 */
- struct list pending_timers; /* list of pending timers */
- struct list expired_timers; /* list of expired timers */
- unsigned int next_timer_id; /* id for the next timer with a 0 window */
- struct timeout_user *timeout; /* timeout for next timer to expire */
- struct thread_input *input; /* thread input descriptor */
- struct hook_table *hooks; /* hook table */
- struct timeval last_get_msg; /* time of last get message call */
- };
- 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 );
- static int msg_queue_signaled( struct object *obj, struct thread *thread );
- static int msg_queue_satisfied( struct object *obj, struct thread *thread );
- static void msg_queue_destroy( struct object *obj );
- static void thread_input_dump( struct object *obj, int verbose );
- static void thread_input_destroy( struct object *obj );
- static void timer_callback( void *private );
- static const struct object_ops msg_queue_ops =
- {
- sizeof(struct msg_queue), /* size */
- msg_queue_dump, /* dump */
- msg_queue_add_queue, /* add_queue */
- msg_queue_remove_queue, /* remove_queue */
- msg_queue_signaled, /* signaled */
- msg_queue_satisfied, /* satisfied */
- no_get_fd, /* get_fd */
- msg_queue_destroy /* destroy */
- };
- static const struct object_ops thread_input_ops =
- {
- sizeof(struct thread_input), /* size */
- thread_input_dump, /* dump */
- no_add_queue, /* add_queue */
- NULL, /* remove_queue */
- NULL, /* signaled */
- NULL, /* satisfied */
- no_get_fd, /* get_fd */
- thread_input_destroy /* destroy */
- };
- /* pointer to input structure of foreground thread */
- static struct thread_input *foreground_input;
- /* set the caret window in a given thread input */
- static void set_caret_window( struct thread_input *input, user_handle_t win )
- {
- input->caret = win;
- input->caret_rect.left = 0;
- input->caret_rect.top = 0;
- input->caret_rect.right = 0;
- input->caret_rect.bottom = 0;
- input->caret_hide = 1;
- input->caret_state = 0;
- }
- /* create a thread input object */
- static struct thread_input *create_thread_input(void)
- {
- struct thread_input *input;
- if ((input = alloc_object( &thread_input_ops )))
- {
- input->focus = 0;
- input->capture = 0;
- input->active = 0;
- input->menu_owner = 0;
- input->move_size = 0;
- input->msg = NULL;
- input->msg_thread = NULL;
- input->msg_list.first = input->msg_list.last = NULL;
- set_caret_window( input, 0 );
- memset( input->keystate, 0, sizeof(input->keystate) );
- }
- return input;
- }
- /* release the thread input data of a given thread */
- static void release_thread_input( struct thread *thread )
- {
- struct thread_input *input = thread->queue->input;
- if (!input) return;
- if (input->msg_thread == thread)
- {
- release_object( input->msg_thread );
- input->msg_thread = NULL;
- input->msg = NULL;
- }
- release_object( input );
- thread->queue->input = NULL;
- }
- /* create a message queue object */
- static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_input *input )
- {
- struct msg_queue *queue;
- int i;
- if (!input && !(input = create_thread_input())) return NULL;
- if ((queue = alloc_object( &msg_queue_ops )))
- {
- queue->wake_bits = 0;
- queue->wake_mask = 0;
- queue->changed_bits = 0;
- queue->changed_mask = 0;
- queue->paint_count = 0;
- queue->recv_result = NULL;
- queue->next_timer_id = 1;
- queue->timeout = NULL;
- queue->input = (struct thread_input *)grab_object( input );
- queue->hooks = NULL;
- gettimeofday( &queue->last_get_msg, NULL );
- list_init( &queue->send_result );
- list_init( &queue->callback_result );
- list_init( &queue->pending_timers );
- list_init( &queue->expired_timers );
- for (i = 0; i < NB_MSG_KINDS; i++)
- queue->msg_list[i].first = queue->msg_list[i].last = NULL;
- thread->queue = queue;
- if (!thread->process->queue)
- thread->process->queue = (struct msg_queue *)grab_object( queue );
- }
- release_object( input );
- return queue;
- }
- /* free the message queue of a thread at thread exit */
- void free_msg_queue( struct thread *thread )
- {
- struct process *process = thread->process;
- remove_thread_hooks( thread );
- if (!thread->queue) return;
- if (process->queue == thread->queue) /* is it the process main queue? */
- {
- release_object( process->queue );
- process->queue = NULL;
- if (process->idle_event)
- {
- set_event( process->idle_event );
- release_object( process->idle_event );
- process->idle_event = NULL;
- }
- }
- release_thread_input( thread );
- release_object( thread->queue );
- thread->queue = NULL;
- }
- /* 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;
- if (!queue) queue = create_msg_queue( thread, NULL );
- if (queue->hooks) release_object( queue->hooks );
- queue->hooks = hooks;
- }
- /* check the queue status */
- inline static int is_signaled( struct msg_queue *queue )
- {
- return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
- }
- /* set some queue bits */
- inline static void set_queue_bits( struct msg_queue *queue, unsigned int bits )
- {
- queue->wake_bits |= bits;
- queue->changed_bits |= bits;
- if (is_signaled( queue )) wake_up( &queue->obj, 0 );
- }
- /* clear some queue bits */
- inline static void clear_queue_bits( struct msg_queue *queue, unsigned int bits )
- {
- queue->wake_bits &= ~bits;
- queue->changed_bits &= ~bits;
- }
- /* check whether msg is a keyboard message */
- inline static int is_keyboard_msg( struct message *msg )
- {
- return (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST);
- }
- /* get the QS_* bit corresponding to a given hardware message */
- inline static int get_hardware_msg_bit( struct message *msg )
- {
- if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
- if (is_keyboard_msg( msg )) return QS_KEY;
- return QS_MOUSEBUTTON;
- }
- /* get the current thread queue, creating it if needed */
- inline static struct msg_queue *get_current_queue(void)
- {
- struct msg_queue *queue = current->queue;
- if (!queue) queue = create_msg_queue( current, NULL );
- return queue;
- }
- /* append a message to the end of a list */
- inline static void append_message( struct message_list *list, struct message *msg )
- {
- msg->next = NULL;
- if ((msg->prev = list->last)) msg->prev->next = msg;
- else list->first = msg;
- list->last = msg;
- }
- /* unlink a message from a list it */
- inline static void unlink_message( struct message_list *list, struct message *msg )
- {
- if (msg->next) msg->next->prev = msg->prev;
- else list->last = msg->prev;
- if (msg->prev) msg->prev->next = msg->next;
- else list->first = msg->next;
- }
- /* try to merge a message with the last in the list; return 1 if successful */
- static int merge_message( struct thread_input *input, const struct message *msg )
- {
- struct message *prev = input->msg_list.last;
- if (!prev) return 0;
- if (input->msg == prev) return 0;
- if (prev->result) return 0;
- if (prev->win != msg->win) return 0;
- 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;
- prev->x = msg->x;
- prev->y = msg->y;
- prev->time = msg->time;
- prev->info = msg->info;
- return 1;
- }
- /* free a result structure */
- static void free_result( struct message_result *result )
- {
- if (result->timeout) remove_timeout_user( result->timeout );
- if (result->data) free( result->data );
- if (result->callback_msg) free( result->callback_msg );
- free( result );
- }
- /* 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 );
- }
- /* store the message result in the appropriate structure */
- static void store_message_result( struct message_result *res, unsigned int result,
- unsigned int error )
- {
- res->result = result;
- res->error = error;
- res->replied = 1;
- if (res->timeout)
- {
- remove_timeout_user( res->timeout );
- res->timeout = NULL;
- }
- if (res->sender)
- {
- if (res->callback_msg)
- {
- /* queue the callback message in the sender queue */
- res->callback_msg->lparam = result;
- append_message( &res->sender->msg_list[SEND_MESSAGE], res->callback_msg );
- 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 );
- }
- }
- }
- /* free a message when deleting a queue or window */
- static void free_message( struct message *msg )
- {
- struct message_result *result = msg->result;
- if (result)
- {
- if (result->sender)
- {
- result->receiver = NULL;
- store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ );
- }
- else free_result( result );
- }
- if (msg->data) free( msg->data );
- free( msg );
- }
- /* 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 )
- {
- unlink_message( &queue->msg_list[kind], msg );
- switch(kind)
- {
- case SEND_MESSAGE:
- if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_SENDMESSAGE );
- break;
- case POST_MESSAGE:
- if (!queue->msg_list[kind].first) clear_queue_bits( queue, QS_POSTMESSAGE );
- break;
- }
- free_message( msg );
- }
- /* message timed out without getting a reply */
- static void result_timeout( void *private )
- {
- struct message_result *result = private;
- assert( !result->replied );
- result->timeout = NULL;
- 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,
- struct message *msg, unsigned int timeout,
- void *callback, unsigned int callback_data )
- {
- struct message_result *result = mem_alloc( sizeof(*result) );
- if (result)
- {
- result->sender = send_queue;
- result->receiver = recv_queue;
- result->replied = 0;
- result->data = NULL;
- result->data_size = 0;
- result->timeout = NULL;
- if (msg->type == MSG_CALLBACK)
- {
- struct message *callback_msg = mem_alloc( sizeof(*callback_msg) );
- if (!callback_msg)
- {
- free( result );
- return NULL;
- }
- callback_msg->type = MSG_CALLBACK_RESULT;
- callback_msg->win = msg->win;
- callback_msg->msg = msg->msg;
- callback_msg->wparam = (unsigned int)callback;
- callback_msg->lparam = 0;
- callback_msg->time = get_tick_count();
- callback_msg->x = 0;
- callback_msg->y = 0;
- callback_msg->info = callback_data;
- callback_msg->result = NULL;
- callback_msg->data = NULL;
- callback_msg->data_size = 0;
- result->callback_msg = callback_msg;
- list_add_head( &send_queue->callback_result, &result->sender_entry );
- }
- else
- {
- result->callback_msg = NULL;
- list_add_head( &send_queue->send_result, &result->sender_entry );
- }
- if (timeout != -1)
- {
- struct timeval when;
- gettimeofday( &when, 0 );
- add_timeout( &when, timeout );
- result->timeout = add_timeout_user( &when, result_timeout, result );
- }
- }
- return result;
- }
- /* receive a message, removing it from the sent queue */
- static void receive_message( struct msg_queue *queue, struct message *msg,
- struct get_message_reply *reply )
- {
- struct message_result *result = msg->result;
- 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;
- reply->x = msg->x;
- reply->y = msg->y;
- reply->time = msg->time;
- reply->info = msg->info;
- reply->hook = msg->hook;
- reply->hook_proc = msg->hook_proc;
- if (msg->data) set_reply_data_ptr( msg->data, msg->data_size );
- unlink_message( &queue->msg_list[SEND_MESSAGE], msg );
- /* put the result on the receiver result stack */
- if (result)
- {
- result->recv_next = queue->recv_result;
- queue->recv_result = result;
- }
- free( msg );
- if (!queue->msg_list[SEND_MESSAGE].first) clear_queue_bits( queue, QS_SENDMESSAGE );
- }
- /* set the result of the current received message */
- static void reply_message( struct msg_queue *queue, unsigned int result,
- unsigned int error, int remove, const void *data, size_t len )
- {
- struct message_result *res = queue->recv_result;
- if (remove)
- {
- queue->recv_result = res->recv_next;
- res->receiver = NULL;
- if (!res->sender) /* no one waiting for it */
- {
- free_result( res );
- return;
- }
- }
- if (!res->replied)
- {
- if (len && (res->data = memdup( data, len ))) res->data_size = len;
- store_message_result( res, result, error );
- }
- }
- /* 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;
- struct message_list *list = &queue->msg_list[POST_MESSAGE];
- /* check against the filters */
- for (msg = list->first; msg; msg = msg->next)
- {
- if (msg->msg == WM_QUIT) break; /* WM_QUIT is never filtered */
- if (win && msg->win && msg->win != win && !is_child_window( win, msg->win )) continue;
- if (msg->msg < first) continue;
- if (msg->msg > last) continue;
- break; /* found one */
- }
- if (!msg) return 0;
- /* return it to the app */
- 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;
- reply->x = msg->x;
- reply->y = msg->y;
- reply->time = msg->time;
- reply->info = msg->info;
- if (flags & GET_MSG_REMOVE)
- {
- 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;
- }
- /* empty a message list and free all the messages */
- static void empty_msg_list( struct message_list *list )
- {
- struct message *msg = list->first;
- while (msg)
- {
- struct message *next = msg->next;
- free_message( msg );
- msg = next;
- }
- }
- /* cleanup all pending results when deleting a queue */
- static void cleanup_results( struct msg_queue *queue )
- {
- struct list *entry;
- while ((entry = list_head( &queue->send_result )) != NULL)
- {
- remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
- }
- while ((entry = list_head( &queue->callback_result )) != NULL)
- {
- remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) );
- }
- while (queue->recv_result)
- reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
- }
- /* check if the thread owning the queue is hung (not checking for messages) */
- static int is_queue_hung( struct msg_queue *queue )
- {
- struct timeval now;
- struct wait_queue_entry *entry;
- gettimeofday( &now, NULL );
- if (now.tv_sec - queue->last_get_msg.tv_sec <= 5)
- return 0; /* less than 5 seconds since last get message -> not hung */
- for (entry = queue->obj.head; entry; entry = entry->next)
- {
- if (entry->thread->queue == queue)
- return 0; /* thread is waiting on queue -> not hung */
- }
- return 1;
- }
- static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
- {
- struct msg_queue *queue = (struct msg_queue *)obj;
- struct process *process = entry->thread->process;
- /* a thread can only wait on its own queue */
- if (entry->thread->queue != queue)
- {
- set_error( STATUS_ACCESS_DENIED );
- return 0;
- }
- /* if waiting on the main process queue, set the idle event */
- if (process->queue == queue)
- {
- if (process->idle_event) set_event( process->idle_event );
- }
- 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;
- struct process *process = entry->thread->process;
- remove_queue( obj, entry );
- assert( entry->thread->queue == queue );
- /* if waiting on the main process queue, reset the idle event */
- if (process->queue == queue)
- {
- if (process->idle_event) reset_event( process->idle_event );
- }
- }
- static void msg_queue_dump( struct object *obj, int verbose )
- {
- struct msg_queue *queue = (struct msg_queue *)obj;
- fprintf( stderr, "Msg queue bits=%x mask=%x\n",
- queue->wake_bits, queue->wake_mask );
- }
- static int msg_queue_signaled( struct object *obj, struct thread *thread )
- {
- struct msg_queue *queue = (struct msg_queue *)obj;
- return is_signaled( queue );
- }
- static int msg_queue_satisfied( struct object *obj, struct thread *thread )
- {
- struct msg_queue *queue = (struct msg_queue *)obj;
- queue->wake_mask = 0;
- queue->changed_mask = 0;
- return 0; /* Not abandoned */
- }
- static void msg_queue_destroy( struct object *obj )
- {
- struct msg_queue *queue = (struct msg_queue *)obj;
- struct list *ptr;
- int i;
- cleanup_results( queue );
- for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
- while ((ptr = list_head( &queue->pending_timers )))
- {
- 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 );
- free( timer );
- }
- if (queue->timeout) remove_timeout_user( queue->timeout );
- if (queue->input) release_object( queue->input );
- if (queue->hooks) release_object( queue->hooks );
- }
- static void thread_input_dump( struct object *obj, int verbose )
- {
- struct thread_input *input = (struct thread_input *)obj;
- fprintf( stderr, "Thread input focus=%p capture=%p active=%p\n",
- input->focus, input->capture, input->active );
- }
- static void thread_input_destroy( struct object *obj )
- {
- struct thread_input *input = (struct thread_input *)obj;
- if (foreground_input == input) foreground_input = NULL;
- if (input->msg_thread) release_object( input->msg_thread );
- empty_msg_list( &input->msg_list );
- }
- /* fix the thread input data when a window is destroyed */
- inline static void thread_input_cleanup_window( struct msg_queue *queue, user_handle_t window )
- {
- 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;
- if (window == input->caret) set_caret_window( input, 0 );
- }
- /* 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;
- }
- /* attach two thread input data structures */
- int attach_thread_input( struct thread *thread_from, struct thread *thread_to )
- {
- struct thread_input *input;
- if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0;
- input = (struct thread_input *)grab_object( thread_to->queue->input );
- if (thread_from->queue)
- {
- release_thread_input( thread_from );
- thread_from->queue->input = input;
- }
- else
- {
- if (!(thread_from->queue = create_msg_queue( thread_from, input ))) return 0;
- }
- memset( input->keystate, 0, sizeof(input->keystate) );
- return 1;
- }
- /* detach two thread input data structures */
- static void detach_thread_input( struct thread *thread_from, struct thread *thread_to )
- {
- struct thread_input *input;
- if (!thread_from->queue || !thread_to->queue ||
- thread_from->queue->input != thread_to->queue->input)
- {
- set_error( STATUS_ACCESS_DENIED );
- return;
- }
- if ((input = create_thread_input()))
- {
- release_thread_input( thread_from );
- thread_from->queue->input = input;
- }
- }
- /* set the next timer to expire */
- static void set_next_timer( struct msg_queue *queue )
- {
- struct list *ptr;
- if (queue->timeout)
- {
- remove_timeout_user( queue->timeout );
- queue->timeout = NULL;
- }
- if ((ptr = list_head( &queue->pending_timers )))
- {
- struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
- queue->timeout = add_timeout_user( &timer->when, timer_callback, queue );
- }
- /* set/clear QS_TIMER bit */
- if (list_empty( &queue->expired_timers ))
- clear_queue_bits( queue, QS_TIMER );
- else
- set_queue_bits( queue, QS_TIMER );
- }
- /* find a timer from its window and id */
- static struct timer *find_timer( struct msg_queue *queue, user_handle_t win,
- unsigned int msg, unsigned int id )
- {
- 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;
- }
- /* callback for the next timer expiration */
- static void timer_callback( void *private )
- {
- struct msg_queue *queue = private;
- struct list *ptr;
- queue->timeout = NULL;
- /* move on to the next timer */
- ptr = list_head( &queue->pending_timers );
- list_remove( ptr );
- list_add_tail( &queue->expired_timers, ptr );
- set_next_timer( queue );
- }
- /* link a timer at its rightful place in the queue list */
- static void link_timer( struct msg_queue *queue, struct timer *timer )
- {
- struct list *ptr;
- for (ptr = queue->pending_timers.next; ptr != &queue->pending_timers; ptr = ptr->next)
- {
- struct timer *t = LIST_ENTRY( ptr, struct timer, entry );
- if (!time_before( &t->when, &timer->when )) break;
- }
- list_add_before( ptr, &timer->entry );
- }
- /* remove a timer from the queue timer list and free it */
- static void free_timer( struct msg_queue *queue, struct timer *timer )
- {
- list_remove( &timer->entry );
- free( timer );
- set_next_timer( queue );
- }
- /* restart an expired timer */
- static void restart_timer( struct msg_queue *queue, struct timer *timer )
- {
- struct timeval now;
- list_remove( &timer->entry );
- gettimeofday( &now, 0 );
- while (!time_before( &now, &timer->when )) add_timeout( &timer->when, timer->rate );
- link_timer( queue, timer );
- set_next_timer( queue );
- }
- /* find an expired timer matching the filtering parameters */
- static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t win,
- unsigned int get_first, unsigned int get_last,
- int remove )
- {
- struct list *ptr;
- LIST_FOR_EACH( ptr, &queue->expired_timers )
- {
- struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
- if (win && timer->win != win) continue;
- if (timer->msg >= get_first && timer->msg <= get_last)
- {
- 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)
- {
- timer->rate = max( rate, 1 );
- gettimeofday( &timer->when, 0 );
- add_timeout( &timer->when, rate );
- link_timer( queue, timer );
- /* check if we replaced the next timer */
- if (list_head( &queue->pending_timers ) == &timer->entry) set_next_timer( queue );
- }
- return timer;
- }
- /* change the input key state for a given key */
- static void set_input_key_state( struct thread_input *input, unsigned char key, int down )
- {
- if (down)
- {
- if (!(input->keystate[key] & 0x80)) input->keystate[key] ^= 0x01;
- input->keystate[key] |= 0x80;
- }
- else input->keystate[key] &= ~0x80;
- }
- /* update the input key state for a keyboard message */
- static void update_input_key_state( struct thread_input *input, const struct message *msg )
- {
- unsigned char key;
- int down = 0, extended;
- switch (msg->msg)
- {
- case WM_LBUTTONDOWN:
- down = 1;
- /* fall through */
- case WM_LBUTTONUP:
- set_input_key_state( input, VK_LBUTTON, down );
- break;
- case WM_MBUTTONDOWN:
- down = 1;
- /* fall through */
- case WM_MBUTTONUP:
- set_input_key_state( input, VK_MBUTTON, down );
- break;
- case WM_RBUTTONDOWN:
- down = 1;
- /* fall through */
- case WM_RBUTTONUP:
- set_input_key_state( input, VK_RBUTTON, down );
- break;
- case WM_KEYDOWN:
- case WM_SYSKEYDOWN:
- down = 1;
- /* fall through */
- case WM_KEYUP:
- case WM_SYSKEYUP:
- key = (unsigned char)msg->wparam;
- extended = ((msg->lparam >> 16) & KF_EXTENDED) != 0;
- set_input_key_state( input, key, down );
- switch(key)
- {
- case VK_SHIFT:
- set_input_key_state( input, extended ? VK_RSHIFT : VK_LSHIFT, down );
- break;
- case VK_CONTROL:
- set_input_key_state( input, extended ? VK_RCONTROL : VK_LCONTROL, down );
- break;
- case VK_MENU:
- set_input_key_state( input, extended ? VK_RMENU : VK_LMENU, down );
- break;
- }
- break;
- }
- }
- /* release the hardware message currently being processed by the given thread */
- static void release_hardware_message( struct thread *thread, int remove )
- {
- struct thread_input *input = thread->queue->input;
- if (input->msg_thread != thread) return;
- if (remove)
- {
- struct message *other;
- int clr_bit;
- update_input_key_state( input, input->msg );
- unlink_message( &input->msg_list, input->msg );
- clr_bit = get_hardware_msg_bit( input->msg );
- for (other = input->msg_list.first; other; other = other->next)
- if (get_hardware_msg_bit( other ) == clr_bit) break;
- if (!other) clear_queue_bits( thread->queue, clr_bit );
- free_message( input->msg );
- }
- release_object( input->msg_thread );
- input->msg = NULL;
- input->msg_thread = NULL;
- }
- /* find the window that should receive a given hardware message */
- static user_handle_t find_hardware_message_window( struct thread_input *input, struct message *msg,
- unsigned int *msg_code )
- {
- user_handle_t win = 0;
- *msg_code = msg->msg;
- if (is_keyboard_msg( msg ))
- {
- if (input && !(win = input->focus))
- {
- win = input->active;
- if (*msg_code < WM_SYSKEYDOWN) *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN;
- }
- }
- else /* mouse message */
- {
- if (!input || !(win = input->capture))
- {
- if (!(win = msg->win) || !is_window_visible( win ))
- win = window_from_point( msg->x, msg->y );
- }
- }
- return win;
- }
- /* queue a hardware message into a given thread input */
- static void queue_hardware_message( struct msg_queue *queue, struct message *msg )
- {
- user_handle_t win;
- struct thread *thread;
- struct thread_input *input;
- unsigned int msg_code;
- win = find_hardware_message_window( queue ? queue->input : foreground_input, msg, &msg_code );
- if (!win || !(thread = get_window_thread(win)))
- {
- free( msg );
- return;
- }
- input = thread->queue->input;
- if (msg->msg == WM_MOUSEMOVE && merge_message( input, msg )) free( msg );
- else
- {
- append_message( &input->msg_list, msg );
- set_queue_bits( thread->queue, get_hardware_msg_bit(msg) );
- }
- release_object( thread );
- }
- /* find a hardware message for the given queue */
- static int get_hardware_message( struct thread *thread, struct message *first,
- user_handle_t filter_win, struct get_message_reply *reply )
- {
- struct thread_input *input = thread->queue->input;
- struct thread *win_thread;
- struct message *msg;
- user_handle_t win;
- int clear_bits, got_one = 0;
- unsigned int msg_code;
- if (input->msg_thread && input->msg_thread != thread)
- return 0; /* locked by another thread */
- if (!first)
- {
- msg = input->msg_list.first;
- clear_bits = QS_KEY | QS_MOUSEMOVE | QS_MOUSEBUTTON;
- }
- else
- {
- msg = first->next;
- clear_bits = 0; /* don't clear bits if we don't go through the whole list */
- }
- while (msg)
- {
- win = find_hardware_message_window( input, msg, &msg_code );
- if (!win || !(win_thread = get_window_thread( win )))
- {
- /* no window at all, remove it */
- struct message *next = msg->next;
- update_input_key_state( input, msg );
- unlink_message( &input->msg_list, msg );
- free_message( msg );
- msg = next;
- continue;
- }
- if (win_thread != thread)
- {
- /* wake the other thread */
- set_queue_bits( win_thread->queue, get_hardware_msg_bit(msg) );
- release_object( win_thread );
- got_one = 1;
- msg = msg->next;
- continue;
- }
- /* if we already got a message for another thread, or if it doesn't
- * match the filter we skip it (filter is only checked for keyboard
- * messages since the dest window for a mouse message depends on hittest)
- */
- if (got_one ||
- (filter_win && is_keyboard_msg(msg) &&
- win != filter_win && !is_child_window( filter_win, win )))
- {
- clear_bits &= ~get_hardware_msg_bit( msg );
- release_object( win_thread );
- msg = msg->next;
- continue;
- }
- /* now we can return it */
- if (!input->msg_thread) input->msg_thread = win_thread;
- else release_object( win_thread );
- input->msg = msg;
- reply->type = MSG_HARDWARE;
- reply->win = win;
- reply->msg = msg_code;
- reply->wparam = msg->wparam;
- reply->lparam = msg->lparam;
- reply->x = msg->x;
- reply->y = msg->y;
- reply->time = msg->time;
- reply->info = msg->info;
- return 1;
- }
- /* nothing found, clear the hardware queue bits */
- clear_queue_bits( thread->queue, clear_bits );
- if (input->msg_thread) release_object( input->msg_thread );
- input->msg = NULL;
- input->msg_thread = NULL;
- return 0;
- }
- /* 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 );
- }
- /* remove all messages and timers belonging to a certain window */
- void queue_cleanup_window( struct thread *thread, user_handle_t win )
- {
- struct msg_queue *queue = thread->queue;
- struct list *ptr;
- struct message *msg;
- int i;
- if (!queue) return;
- /* remove timers */
- ptr = list_head( &queue->pending_timers );
- while (ptr)
- {
- 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;
- }
- /* remove messages */
- for (i = 0; i < NB_MSG_KINDS; i++)
- {
- msg = queue->msg_list[i].first;
- while (msg)
- {
- struct message *next = msg->next;
- if (msg->win == win) remove_queue_message( queue, msg, i );
- msg = next;
- }
- }
- thread_input_cleanup_window( queue, win );
- }
- /* post a message to a window; used by socket handling */
- void post_message( user_handle_t win, unsigned int message,
- unsigned int wparam, unsigned int 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_POSTED;
- msg->win = get_user_full_handle( win );
- msg->msg = message;
- msg->wparam = wparam;
- msg->lparam = lparam;
- msg->time = get_tick_count();
- msg->x = 0;
- msg->y = 0;
- msg->info = 0;
- msg->result = NULL;
- msg->data = NULL;
- msg->data_size = 0;
- append_message( &thread->queue->msg_list[POST_MESSAGE], msg );
- set_queue_bits( thread->queue, QS_POSTMESSAGE );
- }
- release_object( thread );
- }
- /* post a win event */
- void post_win_event( struct thread *thread, unsigned int event,
- user_handle_t win, unsigned int object_id,
- unsigned int child_id, void *hook_proc,
- const WCHAR *module, size_t module_size,
- user_handle_t hook)
- {
- struct message *msg;
- if (thread->queue && (msg = mem_alloc( sizeof(*msg) )))
- {
- 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->x = 0;
- msg->y = 0;
- msg->info = get_thread_id( current );
- msg->result = NULL;
- msg->hook = hook;
- msg->hook_proc = hook_proc;
- if ((msg->data = malloc( module_size )))
- {
- msg->data_size = module_size;
- memcpy( msg->data, module, module_size );
- if (debug_level > 1)
- fprintf( stderr, "post_win_event: tid %04x event %04x win %p object_id %d child_id %d\n",
- get_thread_id(thread), event, win, object_id, child_id );
- append_message( &thread->queue->msg_list[SEND_MESSAGE], msg );
- set_queue_bits( thread->queue, QS_SENDMESSAGE );
- }
- else
- free( msg );
- }
- }
- /* get the message queue of the current thread */
- DECL_HANDLER(get_msg_queue)
- {
- struct msg_queue *queue = get_current_queue();
- reply->handle = 0;
- if (queue) reply->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
- }
- /* 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;
- reply->wake_bits = queue->wake_bits;
- reply->changed_bits = queue->changed_bits;
- if (is_signaled( queue ))
- {
- /* if skip wait is set, do what would have been done in the subsequent wait */
- if (req->skip_wait) msg_queue_satisfied( &queue->obj, current );
- 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)
- {
- reply->wake_bits = queue->wake_bits;
- reply->changed_bits = queue->changed_bits;
- if (req->clear) queue->changed_bits = 0;
- }
- else reply->wake_bits = reply->changed_bits = 0;
- }
- /* send a message to a thread queue */
- DECL_HANDLER(send_message)
- {
- struct message *msg;
- struct msg_queue *send_queue = get_current_queue();
- struct msg_queue *recv_queue = NULL;
- struct thread *thread = NULL;
- if (req->id)
- {
- if (!(thread = get_thread_from_id( req->id ))) return;
- }
- else if (req->type != MSG_HARDWARE)
- {
- /* only hardware messages are allowed without destination thread */
- set_error( STATUS_INVALID_PARAMETER );
- return;
- }
- if (thread && !(recv_queue = thread->queue))
- {
- set_error( STATUS_INVALID_PARAMETER );
- release_object( thread );
- return;
- }
- if (recv_queue && (req->flags & SEND_MSG_ABORT_IF_HUNG) && is_queue_hung(recv_queue))
- {
- set_error( STATUS_TIMEOUT );
- release_object( thread );
- return;
- }
- if ((msg = mem_alloc( sizeof(*msg) )))
- {
- msg->type = req->type;
- msg->win = get_user_full_handle( req->win );
- msg->msg = req->msg;
- msg->wparam = req->wparam;
- msg->lparam = req->lparam;
- msg->time = req->time;
- msg->x = req->x;
- msg->y = req->y;
- msg->info = req->info;
- msg->result = NULL;
- msg->data = NULL;
- msg->data_size = 0;
- switch(msg->type)
- {
- case MSG_OTHER_PROCESS:
- msg->data_size = get_req_data_size();
- if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size )))
- {
- free( msg );
- break;
- }
- /* fall through */
- case MSG_ASCII:
- case MSG_UNICODE:
- case MSG_CALLBACK:
- if (!(msg->result = alloc_message_result( send_queue, recv_queue, msg,
- req->timeout, req->callback, req->info )))
- {
- free_message( msg );
- break;
- }
- /* fall through */
- case MSG_NOTIFY:
- append_message( &recv_queue->msg_list[SEND_MESSAGE], msg );
- set_queue_bits( recv_queue, QS_SENDMESSAGE );
- break;
- case MSG_POSTED:
- /* needed for posted DDE messages */
- msg->data_size = get_req_data_size();
- if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size )))
- {
- free( msg );
- break;
- }
- append_message( &recv_queue->msg_list[POST_MESSAGE], msg );
- set_queue_bits( recv_queue, QS_POSTMESSAGE );
- break;
- case MSG_HARDWARE:
- queue_hardware_message( recv_queue, msg );
- break;
- case MSG_CALLBACK_RESULT: /* cannot send this one */
- default:
- set_error( STATUS_INVALID_PARAMETER );
- free( msg );
- break;
- }
- }
- if (thread) release_object( thread );
- }
- /* get a message from the current queue */
- DECL_HANDLER(get_message)
- {
- struct timer *timer;
- struct message *msg;
- struct message *first_hw_msg = NULL;
- struct msg_queue *queue = get_current_queue();
- user_handle_t get_win = get_user_full_handle( req->get_win );
- if (!queue) return;
- gettimeofday( &queue->last_get_msg, NULL );
- /* first of all release the hardware input lock if we own it */
- /* we'll grab it again if we find a hardware message */
- if (queue->input->msg_thread == current)
- {
- first_hw_msg = queue->input->msg;
- release_hardware_message( current, 0 );
- }
- /* first check for sent messages */
- if ((msg = queue->msg_list[SEND_MESSAGE].first))
- {
- receive_message( queue, msg, reply );
- return;
- }
- if (req->flags & GET_MSG_SENT_ONLY) goto done; /* nothing else to check */
- /* clear changed bits so we can wait on them if we don't find a message */
- queue->changed_bits = 0;
- /* then check for posted messages */
- if (get_posted_message( queue, get_win, req->get_first, req->get_last, req->flags, reply ))
- return;
- /* then check for any raw hardware message */
- if (get_hardware_message( current, first_hw_msg, get_win, reply ))
- return;
- /* now check for WM_PAINT */
- if (queue->paint_count &&
- (WM_PAINT >= req->get_first) && (WM_PAINT <= req->get_last) &&
- (reply->win = find_window_to_repaint( get_win, current )))
- {
- reply->type = MSG_POSTED;
- reply->msg = WM_PAINT;
- reply->wparam = 0;
- reply->lparam = 0;
- reply->x = 0;
- reply->y = 0;
- reply->time = get_tick_count();
- reply->info = 0;
- return;
- }
- /* now check for timer */
- if ((timer = find_expired_timer( queue, get_win, req->get_first,
- req->get_last, (req->flags & GET_MSG_REMOVE) )))
- {
- reply->type = MSG_POSTED;
- reply->win = timer->win;
- reply->msg = timer->msg;
- reply->wparam = timer->id;
- reply->lparam = timer->lparam;
- reply->x = 0;
- reply->y = 0;
- reply->time = get_tick_count();
- reply->info = 0;
- return;
- }
- done:
- set_error( STATUS_PENDING ); /* FIXME */
- }
- /* reply to a sent message */
- DECL_HANDLER(reply_message)
- {
- if (!current->queue)
- {
- set_error( STATUS_ACCESS_DENIED );
- return;
- }
- if (req->type == MSG_HARDWARE)
- {
- struct thread_input *input = current->queue->input;
- if (input->msg_thread == current) release_hardware_message( current, req->remove );
- else set_error( STATUS_ACCESS_DENIED );
- }
- else if (current->queue->recv_result)
- reply_message( current->queue, req->result, 0, req->remove,
- get_req_data(), get_req_data_size() );
- }
- /* retrieve the reply for the last message sent */
- DECL_HANDLER(get_message_reply)
- {
- struct message_result *result;
- struct list *entry;
- struct msg_queue *queue = current->queue;
- if (queue)
- {
- set_error( STATUS_PENDING );
- reply->result = 0;
- 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)
- {
- if (result->replied)
- {
- reply->result = result->result;
- set_error( result->error );
- if (result->data)
- {
- size_t data_len = min( result->data_size, get_reply_max_size() );
- set_reply_data_ptr( result->data, data_len );
- result->data = NULL;
- result->data_size = 0;
- }
- }
- 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 );
- if (!result->replied) clear_queue_bits( queue, QS_SMRESULT );
- }
- }
- }
- else set_error( STATUS_ACCESS_DENIED );
- }
- /* set a window timer */
- DECL_HANDLER(set_win_timer)
- {
- struct timer *timer;
- struct msg_queue *queue;
- struct thread *thread = NULL;
- user_handle_t win = 0;
- unsigned int id = req->id;
- 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();
- /* find a free id for it */
- do
- {
- id = queue->next_timer_id;
- if (++queue->next_timer_id >= 0x10000) queue->next_timer_id = 1;
- }
- while (find_timer( queue, 0, req->msg, id ));
- }
- if ((timer = set_timer( queue, req->rate )))
- {
- timer->win = win;
- timer->msg = req->msg;
- timer->id = id;
- timer->lparam = req->lparam;
- reply->id = id;
- }
- if (thread) release_object( thread );
- }
- /* kill a window timer */
- DECL_HANDLER(kill_win_timer)
- {
- 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 );
- if (thread->queue && (timer = find_timer( thread->queue, win, req->msg, req->id )))
- free_timer( thread->queue, timer );
- else
- set_error( STATUS_INVALID_PARAMETER );
- release_object( thread );
- }
- /* 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)
- {
- if (req->attach) attach_thread_input( thread_from, thread_to );
- else detach_thread_input( thread_from, thread_to );
- }
- 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;
- struct thread_input *input;
- if (req->tid)
- {
- if (!(thread = get_thread_from_id( req->tid ))) return;
- input = thread->queue ? thread->queue->input : NULL;
- }
- else input = foreground_input; /* get the foreground thread info */
- 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;
- reply->rect = input->caret_rect;
- }
- else
- {
- reply->focus = 0;
- reply->capture = 0;
- reply->active = 0;
- reply->menu_owner = 0;
- reply->move_size = 0;
- reply->caret = 0;
- reply->rect.left = reply->rect.top = reply->rect.right = reply->rect.bottom = 0;
- }
- /* foreground window is active window of foreground thread */
- reply->foreground = foreground_input ? foreground_input->active : 0;
- if (thread) release_object( thread );
- }
- /* retrieve queue keyboard state for a given thread */
- DECL_HANDLER(get_key_state)
- {
- struct thread *thread;
- struct thread_input *input;
- if (!(thread = get_thread_from_id( req->tid ))) return;
- input = thread->queue ? thread->queue->input : NULL;
- if (input)
- {
- if (req->key >= 0) reply->state = input->keystate[req->key & 0xff];
- set_reply_data( input->keystate, min( get_reply_max_size(), sizeof(input->keystate) ));
- }
- release_object( thread );
- }
- /* set queue keyboard state for a given thread */
- DECL_HANDLER(set_key_state)
- {
- struct thread *thread = NULL;
- struct thread_input *input;
- if (!(thread = get_thread_from_id( req->tid ))) return;
- input = thread->queue ? thread->queue->input : NULL;
- if (input)
- {
- size_t size = min( sizeof(input->keystate), get_req_data_size() );
- if (size) memcpy( input->keystate, get_req_data(), size );
- }
- release_object( thread );
- }
- /* set the system foreground window */
- DECL_HANDLER(set_foreground_window)
- {
- struct msg_queue *queue = get_current_queue();
- reply->previous = foreground_input ? foreground_input->active : 0;
- reply->send_msg_old = (reply->previous && foreground_input != queue->input);
- reply->send_msg_new = FALSE;
- if (req->handle)
- {
- struct thread *thread;
- if (is_top_level_window( req->handle ) &&
- ((thread = get_window_thread( req->handle ))))
- {
- foreground_input = thread->queue->input;
- reply->send_msg_new = (foreground_input != queue->input);
- release_object( thread );
- }
- else set_error( STATUS_INVALID_HANDLE );
- }
- else foreground_input = NULL;
- }
- /* 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 );
- }
- }
- /* 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;
- 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;
- }
- }
- /* 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) );
- input->caret_rect.right = req->width;
- input->caret_rect.bottom = req->height;
- }
- }
- /* 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)
- {
- if (req->state == -1) input->caret_state = !input->caret_state;
- else input->caret_state = !!req->state;
- }
- }
|