Mercurial > sdl-ios-xcode
annotate src/thread/amigaos/SDL_thread.c @ 1287:15a89a0c52bf
Date: Tue, 15 Feb 2005 21:28:48 +0900 (JST)
From: "Michael Leonhard"
Subject: [SDL] resize bug on Win32 and patch
This is my first post to this mailing list. In this email I will detail a
bug in the behavior of resizable SDL windows on Win32. Then I will
explain the solution and provide a patch.
Symptoms:
Under Windows, an SDL display created with the SDL_RESIZABLE flag exhibits
quirky behavior when being maximized. The window is resized to the proper
size, but it is shifted upwards about half the height of the title bar.
Similarly, a window whose origin is above the top of the screen will
spontaneously move its upper-left origin upon being resized. After two
such resize-induced moves, the title bar will be entirely off the top edge
of the screen. Subsequently, when the mouse is clicked and released on
the window border, the window will shrink its height spontaneously. This
height shrinkage occurs even if the user did not resize the border.
To observe this curious situation, please invoke:
SDL-1.2.8/test/testwm.exe -resize
Cause:
A pair of integers, SDL_windowX and SDL_windowY, are defined in
video/wincommon/SDL_sysevents.c. They are used by the DirectX video
driver and the DIB video driver:
video/windx5/SDL_dx5video.c
video/windib/SDL_dibvideo.c
As I understand the source code, the primary use of these variables is to
create a rectangle that represents the surface area in CLIENT SPACE.
Client space refers to a coordinate system that originates at the upper
left corner of a Win32 Window's drawable area. This is just inside the
window border and title bar. This client space rectangle, called bounds,
is subsequently converted to screen space with a call to
AdjustWindowRectEx. The problem is found in SDL's handling of the
WM_WINDOWPOSCHANGED message. According to MSDN,
"The WM_WINDOWPOSCHANGED message is sent to a window whose
size, position, or place in the Z order has changed as a
result of a call to the SetWindowPos function or another
window-management function."
I have confirmed that this message is indeed being sent to the SDL window
when the mouse is clicked on the window border, even if the window border
is not dragged.
In video/wincommon/SDL_sysevents.c, on line 464, in response to the
WM_WINDOWPOSCHANGED message, the (potentially) new client rectangle is
obtained. This rectangle is translated into screen coordinates and THEN
assigned to the SDL_windowX and Y variables. Thus screen coordinates are
being assigned to client coordinate variables. Once this is understood,
the solution is apparent: assign SDL_windowX and Y before translating the
rectangle to screen coordinates. This is accomplished by the following
patch.
-Mike_L
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 29 Jan 2006 08:50:06 +0000 |
parents | b8d311d90021 |
children | c9b51268668f |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
769
b8d311d90021
Updated copyright information for 2004 (Happy New Year!)
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
3 Copyright (C) 1997-2004 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Library General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public | |
16 License along with this library; if not, write to the Free | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
21
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 /* System independent thread management routines for SDL */ | |
29 | |
30 #include <stdio.h> | |
31 #include <stdlib.h> | |
32 #include <string.h> | |
33 | |
34 #include "SDL_error.h" | |
35 #include "SDL_mutex.h" | |
36 #include "SDL_thread.h" | |
37 #include "SDL_thread_c.h" | |
38 #include "SDL_systhread.h" | |
39 | |
40 #define ARRAY_CHUNKSIZE 32 | |
41 /* The array of threads currently active in the application | |
42 (except the main thread) | |
43 The manipulation of an array here is safer than using a linked list. | |
44 */ | |
45 static int SDL_maxthreads = 0; | |
46 static int SDL_numthreads = 0; | |
47 static SDL_Thread **SDL_Threads = NULL; | |
48 static struct SignalSemaphore thread_lock; | |
49 int thread_lock_created = 0; | |
50 | |
51 int SDL_ThreadsInit(void) | |
52 { | |
53 InitSemaphore(&thread_lock); | |
54 thread_lock_created=1; | |
55 return 0; | |
56 } | |
57 | |
58 /* This should never be called... | |
59 If this is called by SDL_Quit(), we don't know whether or not we should | |
60 clean up threads here. If any threads are still running after this call, | |
61 they will no longer have access to any per-thread data. | |
62 */ | |
63 void SDL_ThreadsQuit() | |
64 { | |
65 thread_lock_created=0; | |
66 } | |
67 | |
68 /* Routines for manipulating the thread list */ | |
69 static void SDL_AddThread(SDL_Thread *thread) | |
70 { | |
71 SDL_Thread **threads; | |
72 | |
73 /* WARNING: | |
74 If the very first threads are created simultaneously, then | |
75 there could be a race condition causing memory corruption. | |
76 In practice, this isn't a problem because by definition there | |
77 is only one thread running the first time this is called. | |
78 */ | |
79 if ( !thread_lock_created ) { | |
80 if ( SDL_ThreadsInit() < 0 ) { | |
81 return; | |
82 } | |
83 } | |
84 ObtainSemaphore(&thread_lock); | |
85 | |
86 /* Expand the list of threads, if necessary */ | |
87 #ifdef DEBUG_THREADS | |
88 printf("Adding thread (%d already - %d max)\n", | |
89 SDL_numthreads, SDL_maxthreads); | |
90 #endif | |
91 if ( SDL_numthreads == SDL_maxthreads ) { | |
92 threads=(SDL_Thread **)malloc((SDL_maxthreads+ARRAY_CHUNKSIZE)* | |
93 (sizeof *threads)); | |
94 if ( threads == NULL ) { | |
95 SDL_OutOfMemory(); | |
96 goto done; | |
97 } | |
98 memcpy(threads, SDL_Threads, SDL_numthreads*(sizeof *threads)); | |
99 SDL_maxthreads += ARRAY_CHUNKSIZE; | |
100 if ( SDL_Threads ) { | |
101 free(SDL_Threads); | |
102 } | |
103 SDL_Threads = threads; | |
104 } | |
105 SDL_Threads[SDL_numthreads++] = thread; | |
106 done: | |
107 ReleaseSemaphore(&thread_lock); | |
108 } | |
109 | |
110 static void SDL_DelThread(SDL_Thread *thread) | |
111 { | |
112 int i; | |
113 | |
114 if ( thread_lock_created ) { | |
115 ObtainSemaphore(&thread_lock); | |
116 for ( i=0; i<SDL_numthreads; ++i ) { | |
117 if ( thread == SDL_Threads[i] ) { | |
118 break; | |
119 } | |
120 } | |
121 if ( i < SDL_numthreads ) { | |
122 --SDL_numthreads; | |
123 while ( i < SDL_numthreads ) { | |
124 SDL_Threads[i] = SDL_Threads[i+1]; | |
125 ++i; | |
126 } | |
127 #ifdef DEBUG_THREADS | |
128 printf("Deleting thread (%d left - %d max)\n", | |
129 SDL_numthreads, SDL_maxthreads); | |
130 #endif | |
131 } | |
132 ReleaseSemaphore(&thread_lock); | |
133 } | |
134 } | |
135 | |
136 /* The default (non-thread-safe) global error variable */ | |
137 static SDL_error SDL_global_error; | |
138 | |
139 /* Routine to get the thread-specific error variable */ | |
140 SDL_error *SDL_GetErrBuf(void) | |
141 { | |
142 SDL_error *errbuf; | |
143 | |
144 errbuf = &SDL_global_error; | |
145 if ( SDL_Threads ) { | |
146 int i; | |
147 Uint32 this_thread; | |
148 | |
149 this_thread = SDL_ThreadID(); | |
150 ObtainSemaphore(&thread_lock); | |
151 for ( i=0; i<SDL_numthreads; ++i ) { | |
152 if ( this_thread == SDL_Threads[i]->threadid ) { | |
153 errbuf = &SDL_Threads[i]->errbuf; | |
154 break; | |
155 } | |
156 } | |
157 ReleaseSemaphore(&thread_lock); | |
158 } | |
159 return(errbuf); | |
160 } | |
161 | |
162 | |
163 /* Arguments and callback to setup and run the user thread function */ | |
164 typedef struct { | |
165 int (*func)(void *); | |
166 void *data; | |
167 SDL_Thread *info; | |
168 struct Task *wait; | |
169 } thread_args; | |
170 | |
171 void SDL_RunThread(void *data) | |
172 { | |
173 thread_args *args; | |
174 int (*userfunc)(void *); | |
175 void *userdata; | |
176 int *statusloc; | |
177 | |
178 /* Perform any system-dependent setup | |
179 - this function cannot fail, and cannot use SDL_SetError() | |
180 */ | |
181 SDL_SYS_SetupThread(); | |
182 | |
183 /* Get the thread id */ | |
184 args = (thread_args *)data; | |
185 args->info->threadid = SDL_ThreadID(); | |
186 | |
187 /* Figure out what function to run */ | |
188 userfunc = args->func; | |
189 userdata = args->data; | |
190 statusloc = &args->info->status; | |
191 | |
192 /* Wake up the parent thread */ | |
193 Signal(args->wait,SIGBREAKF_CTRL_E); | |
194 | |
195 /* Run the function */ | |
196 *statusloc = userfunc(userdata); | |
197 } | |
198 | |
199 SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data) | |
200 { | |
201 SDL_Thread *thread; | |
202 thread_args *args; | |
203 int ret; | |
204 | |
205 /* Allocate memory for the thread info structure */ | |
206 thread = (SDL_Thread *)malloc(sizeof(*thread)); | |
207 if ( thread == NULL ) { | |
208 SDL_OutOfMemory(); | |
209 return(NULL); | |
210 } | |
211 memset(thread, 0, (sizeof *thread)); | |
212 thread->status = -1; | |
213 | |
214 /* Set up the arguments for the thread */ | |
215 args = (thread_args *)malloc(sizeof(*args)); | |
216 if ( args == NULL ) { | |
217 SDL_OutOfMemory(); | |
218 free(thread); | |
219 return(NULL); | |
220 } | |
221 args->func = fn; | |
222 args->data = data; | |
223 args->info = thread; | |
224 args->wait = FindTask(NULL); | |
225 if ( args->wait == NULL ) { | |
226 free(thread); | |
227 free(args); | |
228 SDL_OutOfMemory(); | |
229 return(NULL); | |
230 } | |
231 | |
232 /* Add the thread to the list of available threads */ | |
233 SDL_AddThread(thread); | |
234 | |
235 D(bug("Starting thread...\n")); | |
236 | |
237 /* Create the thread and go! */ | |
238 ret = SDL_SYS_CreateThread(thread, args); | |
239 if ( ret >= 0 ) { | |
240 D(bug("Waiting for thread CTRL_E...\n")); | |
241 /* Wait for the thread function to use arguments */ | |
242 Wait(SIGBREAKF_CTRL_E); | |
243 D(bug(" Arrived.")); | |
244 } else { | |
245 /* Oops, failed. Gotta free everything */ | |
246 SDL_DelThread(thread); | |
247 free(thread); | |
248 thread = NULL; | |
249 } | |
250 free(args); | |
251 | |
252 /* Everything is running now */ | |
253 return(thread); | |
254 } | |
255 | |
256 void SDL_WaitThread(SDL_Thread *thread, int *status) | |
257 { | |
258 if ( thread ) { | |
259 SDL_SYS_WaitThread(thread); | |
260 if ( status ) { | |
261 *status = thread->status; | |
262 } | |
263 SDL_DelThread(thread); | |
264 free(thread); | |
265 } | |
266 } | |
267 | |
21
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
268 Uint32 SDL_GetThreadID(SDL_Thread *thread) |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
269 { |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
270 Uint32 id; |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
271 |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
272 if ( thread ) { |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
273 id = thread->threadid; |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
274 } else { |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
275 id = SDL_ThreadID(); |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
276 } |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
277 return(id); |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
278 } |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
279 |
0 | 280 void SDL_KillThread(SDL_Thread *thread) |
281 { | |
282 if ( thread ) { | |
283 SDL_SYS_KillThread(thread); | |
284 SDL_WaitThread(thread, NULL); | |
285 } | |
286 } | |
287 |