Mercurial > sdl-ios-xcode
annotate src/cdrom/openbsd/SDL_syscdrom.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 | 0f3aa6ab3341 |
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:
25
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 /* Functions for system-level CD-ROM audio control */ | |
29 | |
30 #include <sys/types.h> | |
31 #include <sys/ioctl.h> | |
32 #include <stdlib.h> | |
33 #include <sys/stat.h> | |
34 #include <fcntl.h> | |
35 #include <stdio.h> | |
36 #include <string.h> | |
37 #include <errno.h> | |
38 #include <unistd.h> | |
1
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
39 #include <sys/ioctl.h> |
0 | 40 #include <sys/cdio.h> |
41 | |
42 #include "SDL_error.h" | |
43 #include "SDL_cdrom.h" | |
44 #include "SDL_syscdrom.h" | |
45 | |
46 | |
47 /* The maximum number of CD-ROM drives we'll detect */ | |
48 #define MAX_DRIVES 16 | |
49 | |
50 /* A list of available CD-ROM drives */ | |
51 static char *SDL_cdlist[MAX_DRIVES]; | |
52 static dev_t SDL_cdmode[MAX_DRIVES]; | |
53 | |
54 /* The system-dependent CD control functions */ | |
55 static const char *SDL_SYS_CDName(int drive); | |
56 static int SDL_SYS_CDOpen(int drive); | |
57 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | |
58 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | |
59 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | |
60 static int SDL_SYS_CDPause(SDL_CD *cdrom); | |
61 static int SDL_SYS_CDResume(SDL_CD *cdrom); | |
62 static int SDL_SYS_CDStop(SDL_CD *cdrom); | |
63 static int SDL_SYS_CDEject(SDL_CD *cdrom); | |
64 static void SDL_SYS_CDClose(SDL_CD *cdrom); | |
65 | |
66 /* Some ioctl() errno values which occur when the tray is empty */ | |
67 #define ERRNO_TRAYEMPTY(errno) \ | |
1
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
68 ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL) || \ |
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
69 (errno == ENODEV)) |
0 | 70 |
71 /* Check a drive to see if it is a CD-ROM */ | |
72 static int CheckDrive(char *drive, struct stat *stbuf) | |
73 { | |
74 int is_cd, cdfd; | |
75 struct ioc_read_subchannel info; | |
76 | |
77 /* If it doesn't exist, return -1 */ | |
78 if ( stat(drive, stbuf) < 0 ) { | |
79 return(-1); | |
80 } | |
81 | |
82 /* If it does exist, verify that it's an available CD-ROM */ | |
83 is_cd = 0; | |
84 if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) { | |
85 cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); | |
86 if ( cdfd >= 0 ) { | |
87 info.address_format = CD_MSF_FORMAT; | |
88 info.data_format = CD_CURRENT_POSITION; | |
89 info.data_len = 0; | |
90 info.data = NULL; | |
91 /* Under Linux, EIO occurs when a disk is not present. | |
92 This isn't 100% reliable, so we use the USE_MNTENT | |
93 code above instead. | |
94 */ | |
95 if ( (ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) || | |
96 ERRNO_TRAYEMPTY(errno) ) { | |
97 is_cd = 1; | |
98 } | |
99 close(cdfd); | |
100 } | |
1
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
101 else if (ERRNO_TRAYEMPTY(errno)) |
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
102 is_cd = 1; |
0 | 103 } |
104 return(is_cd); | |
105 } | |
106 | |
107 /* Add a CD-ROM drive to our list of valid drives */ | |
108 static void AddDrive(char *drive, struct stat *stbuf) | |
109 { | |
110 int i; | |
111 | |
112 if ( SDL_numcds < MAX_DRIVES ) { | |
113 /* Check to make sure it's not already in our list. | |
114 This can happen when we see a drive via symbolic link. | |
115 */ | |
116 for ( i=0; i<SDL_numcds; ++i ) { | |
117 if ( stbuf->st_rdev == SDL_cdmode[i] ) { | |
118 #ifdef DEBUG_CDROM | |
119 fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); | |
120 #endif | |
121 return; | |
122 } | |
123 } | |
124 | |
125 /* Add this drive to our list */ | |
126 i = SDL_numcds; | |
127 SDL_cdlist[i] = (char *)malloc(strlen(drive)+1); | |
128 if ( SDL_cdlist[i] == NULL ) { | |
129 SDL_OutOfMemory(); | |
130 return; | |
131 } | |
132 strcpy(SDL_cdlist[i], drive); | |
133 SDL_cdmode[i] = stbuf->st_rdev; | |
134 ++SDL_numcds; | |
135 #ifdef DEBUG_CDROM | |
136 fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | |
137 #endif | |
138 } | |
139 } | |
140 | |
141 int SDL_SYS_CDInit(void) | |
142 { | |
143 static char *checklist[] = { | |
1
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
144 #ifdef __OpenBSD__ |
25
3fbf86244fd2
Date: Wed, 9 May 2001 18:03:20 -0600
Sam Lantinga <slouken@lokigames.com>
parents:
1
diff
changeset
|
145 "?0 cd?c", "cdrom", NULL |
1026
0f3aa6ab3341
Select patches included from The NetBSD Package Collection (www.pkgsrc.org)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
146 #elif defined(__NetBSD__) |
0f3aa6ab3341
Select patches included from The NetBSD Package Collection (www.pkgsrc.org)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
147 "?0 cd?d", "?0 cd?c", "cdrom", NULL |
1
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
148 #else |
0 | 149 "?0 cd?c", "?0 acd?c", "cdrom", NULL |
1
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
150 #endif |
0 | 151 }; |
152 char *SDLcdrom; | |
153 int i, j, exists; | |
154 char drive[32]; | |
155 struct stat stbuf; | |
156 | |
157 /* Fill in our driver capabilities */ | |
158 SDL_CDcaps.Name = SDL_SYS_CDName; | |
159 SDL_CDcaps.Open = SDL_SYS_CDOpen; | |
160 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | |
161 SDL_CDcaps.Status = SDL_SYS_CDStatus; | |
162 SDL_CDcaps.Play = SDL_SYS_CDPlay; | |
163 SDL_CDcaps.Pause = SDL_SYS_CDPause; | |
164 SDL_CDcaps.Resume = SDL_SYS_CDResume; | |
165 SDL_CDcaps.Stop = SDL_SYS_CDStop; | |
166 SDL_CDcaps.Eject = SDL_SYS_CDEject; | |
167 SDL_CDcaps.Close = SDL_SYS_CDClose; | |
168 | |
169 /* Look in the environment for our CD-ROM drive list */ | |
170 SDLcdrom = getenv("SDL_CDROM"); /* ':' separated list of devices */ | |
171 if ( SDLcdrom != NULL ) { | |
172 char *cdpath, *delim; | |
173 cdpath = malloc(strlen(SDLcdrom)+1); | |
174 if ( cdpath != NULL ) { | |
175 strcpy(cdpath, SDLcdrom); | |
176 SDLcdrom = cdpath; | |
177 do { | |
178 delim = strchr(SDLcdrom, ':'); | |
179 if ( delim ) { | |
180 *delim++ = '\0'; | |
181 } | |
182 if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) { | |
183 AddDrive(SDLcdrom, &stbuf); | |
184 } | |
185 if ( delim ) { | |
186 SDLcdrom = delim; | |
187 } else { | |
188 SDLcdrom = NULL; | |
189 } | |
190 } while ( SDLcdrom ); | |
191 free(cdpath); | |
192 } | |
193 | |
194 /* If we found our drives, there's nothing left to do */ | |
195 if ( SDL_numcds > 0 ) { | |
196 return(0); | |
197 } | |
198 } | |
199 | |
200 /* Scan the system for CD-ROM drives */ | |
201 for ( i=0; checklist[i]; ++i ) { | |
202 if ( checklist[i][0] == '?' ) { | |
203 char *insert; | |
204 exists = 1; | |
205 for ( j=checklist[i][1]; exists; ++j ) { | |
206 sprintf(drive, "/dev/%s", &checklist[i][3]); | |
207 insert = strchr(drive, '?'); | |
208 if ( insert != NULL ) { | |
209 *insert = j; | |
210 } | |
211 switch (CheckDrive(drive, &stbuf)) { | |
212 /* Drive exists and is a CD-ROM */ | |
213 case 1: | |
214 AddDrive(drive, &stbuf); | |
215 break; | |
216 /* Drive exists, but isn't a CD-ROM */ | |
217 case 0: | |
218 break; | |
219 /* Drive doesn't exist */ | |
220 case -1: | |
221 exists = 0; | |
222 break; | |
223 } | |
224 } | |
225 } else { | |
226 sprintf(drive, "/dev/%s", checklist[i]); | |
227 if ( CheckDrive(drive, &stbuf) > 0 ) { | |
228 AddDrive(drive, &stbuf); | |
229 } | |
230 } | |
231 } | |
232 return(0); | |
233 } | |
234 | |
235 /* General ioctl() CD-ROM command function */ | |
236 static int SDL_SYS_CDioctl(int id, int command, void *arg) | |
237 { | |
238 int retval; | |
239 | |
240 retval = ioctl(id, command, arg); | |
241 if ( retval < 0 ) { | |
242 SDL_SetError("ioctl() error: %s", strerror(errno)); | |
243 } | |
244 return(retval); | |
245 } | |
246 | |
247 static const char *SDL_SYS_CDName(int drive) | |
248 { | |
249 return(SDL_cdlist[drive]); | |
250 } | |
251 | |
252 static int SDL_SYS_CDOpen(int drive) | |
253 { | |
254 return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0)); | |
255 } | |
256 | |
257 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | |
258 { | |
259 struct ioc_toc_header toc; | |
260 int i, okay; | |
261 struct ioc_read_toc_entry entry; | |
262 struct cd_toc_entry data; | |
263 | |
264 okay = 0; | |
265 if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0 ) { | |
266 cdrom->numtracks = toc.ending_track-toc.starting_track+1; | |
267 if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | |
268 cdrom->numtracks = SDL_MAX_TRACKS; | |
269 } | |
270 /* Read all the track TOC entries */ | |
271 for ( i=0; i<=cdrom->numtracks; ++i ) { | |
272 if ( i == cdrom->numtracks ) { | |
273 cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */ | |
274 } else { | |
275 cdrom->track[i].id = toc.starting_track+i; | |
276 } | |
277 entry.starting_track = cdrom->track[i].id; | |
278 entry.address_format = CD_MSF_FORMAT; | |
279 entry.data_len = sizeof(data); | |
280 entry.data = &data; | |
281 if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS, | |
282 &entry) < 0 ) { | |
283 break; | |
284 } else { | |
285 cdrom->track[i].type = data.control; | |
286 cdrom->track[i].offset = MSF_TO_FRAMES( | |
287 data.addr.msf.minute, | |
288 data.addr.msf.second, | |
289 data.addr.msf.frame); | |
290 cdrom->track[i].length = 0; | |
291 if ( i > 0 ) { | |
292 cdrom->track[i-1].length = | |
293 cdrom->track[i].offset- | |
294 cdrom->track[i-1].offset; | |
295 } | |
296 } | |
297 } | |
298 if ( i == (cdrom->numtracks+1) ) { | |
299 okay = 1; | |
300 } | |
301 } | |
302 return(okay ? 0 : -1); | |
303 } | |
304 | |
305 /* Get CD-ROM status */ | |
306 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | |
307 { | |
308 CDstatus status; | |
309 struct ioc_toc_header toc; | |
310 struct ioc_read_subchannel info; | |
311 struct cd_sub_channel_info data; | |
312 | |
313 info.address_format = CD_MSF_FORMAT; | |
314 info.data_format = CD_CURRENT_POSITION; | |
315 info.track = 0; | |
316 info.data_len = sizeof(data); | |
317 info.data = &data; | |
318 if ( ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0 ) { | |
319 if ( ERRNO_TRAYEMPTY(errno) ) { | |
320 status = CD_TRAYEMPTY; | |
321 } else { | |
322 status = CD_ERROR; | |
323 } | |
324 } else { | |
325 switch (data.header.audio_status) { | |
326 case CD_AS_AUDIO_INVALID: | |
327 case CD_AS_NO_STATUS: | |
328 /* Try to determine if there's a CD available */ | |
329 if (ioctl(cdrom->id,CDIOREADTOCHEADER,&toc)==0) | |
330 status = CD_STOPPED; | |
331 else | |
332 status = CD_TRAYEMPTY; | |
333 break; | |
334 case CD_AS_PLAY_COMPLETED: | |
335 status = CD_STOPPED; | |
336 break; | |
337 case CD_AS_PLAY_IN_PROGRESS: | |
338 status = CD_PLAYING; | |
339 break; | |
340 case CD_AS_PLAY_PAUSED: | |
341 status = CD_PAUSED; | |
342 break; | |
343 default: | |
344 status = CD_ERROR; | |
345 break; | |
346 } | |
347 } | |
348 if ( position ) { | |
349 if ( status == CD_PLAYING || (status == CD_PAUSED) ) { | |
350 *position = MSF_TO_FRAMES( | |
351 data.what.position.absaddr.msf.minute, | |
352 data.what.position.absaddr.msf.second, | |
353 data.what.position.absaddr.msf.frame); | |
354 } else { | |
355 *position = 0; | |
356 } | |
357 } | |
358 return(status); | |
359 } | |
360 | |
361 /* Start play */ | |
362 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | |
363 { | |
364 struct ioc_play_msf playtime; | |
365 | |
366 FRAMES_TO_MSF(start, | |
367 &playtime.start_m, &playtime.start_s, &playtime.start_f); | |
368 FRAMES_TO_MSF(start+length, | |
369 &playtime.end_m, &playtime.end_s, &playtime.end_f); | |
370 #ifdef DEBUG_CDROM | |
371 fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", | |
372 playtime.start_m, playtime.start_s, playtime.start_f, | |
373 playtime.end_m, playtime.end_s, playtime.end_f); | |
374 #endif | |
375 ioctl(cdrom->id, CDIOCSTART, 0); | |
376 return(SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime)); | |
377 } | |
378 | |
379 /* Pause play */ | |
380 static int SDL_SYS_CDPause(SDL_CD *cdrom) | |
381 { | |
382 return(SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0)); | |
383 } | |
384 | |
385 /* Resume play */ | |
386 static int SDL_SYS_CDResume(SDL_CD *cdrom) | |
387 { | |
388 return(SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0)); | |
389 } | |
390 | |
391 /* Stop play */ | |
392 static int SDL_SYS_CDStop(SDL_CD *cdrom) | |
393 { | |
394 return(SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0)); | |
395 } | |
396 | |
397 /* Eject the CD-ROM */ | |
398 static int SDL_SYS_CDEject(SDL_CD *cdrom) | |
399 { | |
400 return(SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0)); | |
401 } | |
402 | |
403 /* Close the CD-ROM handle */ | |
404 static void SDL_SYS_CDClose(SDL_CD *cdrom) | |
405 { | |
406 close(cdrom->id); | |
407 } | |
408 | |
409 void SDL_SYS_CDQuit(void) | |
410 { | |
411 int i; | |
412 | |
413 if ( SDL_numcds > 0 ) { | |
414 for ( i=0; i<SDL_numcds; ++i ) { | |
415 free(SDL_cdlist[i]); | |
416 } | |
417 SDL_numcds = 0; | |
418 } | |
419 } | |
420 |