Do not invalidate the window before the first paint job.
[wine] / windows / queue.c
1 /*
2  * Message queues related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <string.h>
22 #include <signal.h>
23 #include <assert.h>
24 #include "windef.h"
25 #include "wingdi.h"
26 #include "winerror.h"
27 #include "wine/winbase16.h"
28 #include "wine/winuser16.h"
29 #include "queue.h"
30 #include "win.h"
31 #include "user.h"
32 #include "hook.h"
33 #include "thread.h"
34 #include "wine/debug.h"
35 #include "wine/server.h"
36 #include "spy.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(msg);
39
40
41 /***********************************************************************
42  *           QUEUE_Lock
43  *
44  * Function for getting a 32 bit pointer on queue structure. For thread
45  * safeness programmers should use this function instead of GlobalLock to
46  * retrieve a pointer on the structure. QUEUE_Unlock should also be called
47  * when access to the queue structure is not required anymore.
48  */
49 MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue )
50 {
51     MESSAGEQUEUE *queue;
52
53     HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
54     queue = GlobalLock16( hQueue );
55     if ( !queue || (queue->magic != QUEUE_MAGIC) )
56     {
57         HeapUnlock( GetProcessHeap() );
58         return NULL;
59     }
60
61     queue->lockCount++;
62     HeapUnlock( GetProcessHeap() );
63     return queue;
64 }
65
66
67 /***********************************************************************
68  *           QUEUE_Current
69  *
70  * Get the current thread queue, creating it if required.
71  * QUEUE_Unlock is not needed since the queue can only be deleted by
72  * the current thread anyway.
73  */
74 MESSAGEQUEUE *QUEUE_Current(void)
75 {
76     MESSAGEQUEUE *queue;
77     HQUEUE16 hQueue;
78
79     if (!(hQueue = GetThreadQueue16(0)))
80     {
81         if (!(hQueue = InitThreadInput16( 0, 0 ))) return NULL;
82     }
83
84     if ((queue = GlobalLock16( hQueue )))
85     {
86         if (queue->magic != QUEUE_MAGIC) queue = NULL;
87     }
88     return queue;
89 }
90
91
92 /***********************************************************************
93  *           QUEUE_Unlock
94  *
95  * Use with QUEUE_Lock to get a thread safe access to message queue
96  * structure
97  */
98 void QUEUE_Unlock( MESSAGEQUEUE *queue )
99 {
100     if (queue)
101     {
102         HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
103
104         if ( --queue->lockCount == 0 )
105         {
106             if (queue->server_queue)
107                 CloseHandle( queue->server_queue );
108             GlobalFree16( queue->self );
109         }
110
111         HeapUnlock( GetProcessHeap() );
112     }
113 }
114
115
116 /***********************************************************************
117  *           QUEUE_CreateMsgQueue
118  *
119  * Creates a message queue. Doesn't link it into queue list!
120  */
121 static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
122 {
123     HQUEUE16 hQueue;
124     HANDLE handle;
125     MESSAGEQUEUE * msgQueue;
126
127     TRACE_(msg)("(): Creating message queue...\n");
128
129     if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT,
130                                   sizeof(MESSAGEQUEUE) )))
131         return 0;
132
133     msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
134     if ( !msgQueue )
135         return 0;
136
137     if (bCreatePerQData)
138     {
139         SERVER_START_REQ( get_msg_queue )
140         {
141             wine_server_call_err( req );
142             handle = reply->handle;
143         }
144         SERVER_END_REQ;
145         if (!handle)
146         {
147             ERR_(msg)("Cannot get thread queue");
148             GlobalFree16( hQueue );
149             return 0;
150         }
151         msgQueue->server_queue = handle;
152     }
153
154     msgQueue->self = hQueue;
155     msgQueue->lockCount = 1;
156     msgQueue->magic = QUEUE_MAGIC;
157     return hQueue;
158 }
159
160
161 /***********************************************************************
162  *           QUEUE_DeleteMsgQueue
163  *
164  * Unlinks and deletes a message queue.
165  *
166  * Note: We need to mask asynchronous events to make sure PostMessage works
167  * even in the signal handler.
168  */
169 void QUEUE_DeleteMsgQueue(void)
170 {
171     HQUEUE16 hQueue = GetThreadQueue16(0);
172     MESSAGEQUEUE * msgQueue;
173
174     if (!hQueue) return;  /* thread doesn't have a queue */
175
176     TRACE("(): Deleting message queue %04x\n", hQueue);
177
178     if (!(msgQueue = QUEUE_Lock(hQueue)))
179     {
180         ERR("invalid thread queue\n");
181         return;
182     }
183
184     msgQueue->magic = 0;
185     msgQueue->self = 0;
186     SetThreadQueue16( 0, 0 );
187
188     /* free up resource used by MESSAGEQUEUE structure */
189     msgQueue->lockCount--;
190     QUEUE_Unlock( msgQueue );
191 }
192
193
194 /***********************************************************************
195  *              InitThreadInput   (USER.409)
196  */
197 HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
198 {
199     MESSAGEQUEUE *queuePtr;
200     HQUEUE16 hQueue = NtCurrentTeb()->queue;
201
202     if ( !hQueue )
203     {
204         /* Create thread message queue */
205         if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
206         {
207             ERR_(msg)("failed!\n");
208             return FALSE;
209         }
210
211         /* Link new queue into list */
212         queuePtr = QUEUE_Lock( hQueue );
213
214         HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
215         SetThreadQueue16( 0, hQueue );
216         NtCurrentTeb()->queue = hQueue;
217         HeapUnlock( GetProcessHeap() );
218
219         QUEUE_Unlock( queuePtr );
220     }
221
222     return hQueue;
223 }
224
225 /***********************************************************************
226  *              GetQueueStatus (USER32.@)
227  */
228 DWORD WINAPI GetQueueStatus( UINT flags )
229 {
230     DWORD ret = 0;
231
232     SERVER_START_REQ( get_queue_status )
233     {
234         req->clear = 1;
235         wine_server_call( req );
236         ret = MAKELONG( reply->changed_bits & flags, reply->wake_bits & flags );
237     }
238     SERVER_END_REQ;
239     return ret;
240 }
241
242
243 /***********************************************************************
244  *              GetInputState   (USER32.@)
245  */
246 BOOL WINAPI GetInputState(void)
247 {
248     DWORD ret = 0;
249
250     SERVER_START_REQ( get_queue_status )
251     {
252         req->clear = 0;
253         wine_server_call( req );
254         ret = reply->wake_bits & (QS_KEY | QS_MOUSEBUTTON);
255     }
256     SERVER_END_REQ;
257     return ret;
258 }
259
260 /***********************************************************************
261  *              GetMessagePos (USER.119)
262  *              GetMessagePos (USER32.@)
263  *
264  * The GetMessagePos() function returns a long value representing a
265  * cursor position, in screen coordinates, when the last message
266  * retrieved by the GetMessage() function occurs. The x-coordinate is
267  * in the low-order word of the return value, the y-coordinate is in
268  * the high-order word. The application can use the MAKEPOINT()
269  * macro to obtain a POINT structure from the return value.
270  *
271  * For the current cursor position, use GetCursorPos().
272  *
273  * RETURNS
274  *
275  * Cursor position of last message on success, zero on failure.
276  *
277  * CONFORMANCE
278  *
279  * ECMA-234, Win32
280  *
281  */
282 DWORD WINAPI GetMessagePos(void)
283 {
284     MESSAGEQUEUE *queue;
285
286     if (!(queue = QUEUE_Current())) return 0;
287     return queue->GetMessagePosVal;
288 }
289
290
291 /***********************************************************************
292  *              GetMessageTime (USER.120)
293  *              GetMessageTime (USER32.@)
294  *
295  * GetMessageTime() returns the message time for the last message
296  * retrieved by the function. The time is measured in milliseconds with
297  * the same offset as GetTickCount().
298  *
299  * Since the tick count wraps, this is only useful for moderately short
300  * relative time comparisons.
301  *
302  * RETURNS
303  *
304  * Time of last message on success, zero on failure.
305  *
306  * CONFORMANCE
307  *
308  * ECMA-234, Win32
309  *
310  */
311 LONG WINAPI GetMessageTime(void)
312 {
313     MESSAGEQUEUE *queue;
314
315     if (!(queue = QUEUE_Current())) return 0;
316     return queue->GetMessageTimeVal;
317 }
318
319
320 /***********************************************************************
321  *              GetMessageExtraInfo (USER.288)
322  *              GetMessageExtraInfo (USER32.@)
323  */
324 LONG WINAPI GetMessageExtraInfo(void)
325 {
326     MESSAGEQUEUE *queue;
327
328     if (!(queue = QUEUE_Current())) return 0;
329     return queue->GetMessageExtraInfoVal;
330 }