27
27
* Ctrl-F5 = grab mouse (in windowed mode)
29
29
* FIXMEs and TODOs:
30
* - Windows requires an extra mouse event to update the actual cursor image?
30
31
* - Ctr-Tab for suspend/resume but how? SDL does not support that for non-Linux
31
32
* - Ctrl-Fn doesn't generate SDL_KEYDOWN events (SDL bug?)
32
33
* - Mouse acceleration, there is no API in SDL yet for that
33
34
* - Force relative mode in Grab mode even if SDL provides absolute coordinates?
35
35
* - Gamma tables support is likely to be broken here
36
36
* - Events processing is bound to the general emulation thread as SDL requires
37
37
* to PumpEvents() within the same thread as the one that called SetVideoMode().
38
38
* Besides, there can't seem to be a way to call SetVideoMode() from a child thread.
39
* - Refresh performance is still slow. Use SDL_CreateRGBSurface()?
40
39
* - Backport hw cursor acceleration to Basilisk II?
41
40
* - Factor out code
169
* SDL surface locking glue
173
#define SDL_VIDEO_LOCK_VOSF_SURFACE(SURFACE) do { \
174
if ((SURFACE)->flags & (SDL_HWSURFACE | SDL_FULLSCREEN)) \
175
the_host_buffer = (uint8 *)(SURFACE)->pixels; \
178
#define SDL_VIDEO_LOCK_VOSF_SURFACE(SURFACE)
181
#define SDL_VIDEO_LOCK_SURFACE(SURFACE) do { \
182
if (SDL_MUSTLOCK(SURFACE)) { \
183
SDL_LockSurface(SURFACE); \
184
SDL_VIDEO_LOCK_VOSF_SURFACE(SURFACE); \
188
#define SDL_VIDEO_UNLOCK_SURFACE(SURFACE) do { \
189
if (SDL_MUSTLOCK(SURFACE)) \
190
SDL_UnlockSurface(SURFACE); \
161
195
* Framebuffer allocation routines
164
198
static void *vm_acquire_framebuffer(uint32 size)
167
#ifdef DIRECT_ADDRESSING_HACK
168
const uint32 FRAME_BUFFER_BASE = 0x61000000;
169
uint8 *fb = Mac2HostAddr(FRAME_BUFFER_BASE);
170
if (vm_acquire_fixed(fb, size) < 0)
175
200
return vm_acquire(size);
210
* Windows message handler
215
static WNDPROC sdl_window_proc = NULL; // Window proc used by SDL
217
extern void SysMediaArrived(void);
218
extern void SysMediaRemoved(void);
219
extern HWND GetMainWindowHandle(void);
221
static LRESULT CALLBACK windows_message_handler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
224
case WM_DEVICECHANGE:
225
if (wParam == DBT_DEVICEREMOVECOMPLETE) {
226
DEV_BROADCAST_HDR *p = (DEV_BROADCAST_HDR *)lParam;
227
if (p->dbch_devicetype == DBT_DEVTYP_VOLUME)
230
else if (wParam == DBT_DEVICEARRIVAL) {
231
DEV_BROADCAST_HDR *p = (DEV_BROADCAST_HDR *)lParam;
232
if (p->dbch_devicetype == DBT_DEVTYP_VOLUME)
239
return CallWindowProc(sdl_window_proc, hwnd, msg, wParam, lParam);
242
return DefWindowProc(hwnd, msg, wParam, lParam);
185
248
* SheepShaver glue
226
289
// Find Apple mode matching best specified dimensions
227
290
static int find_apple_resolution(int xsize, int ysize)
231
apple_id = APPLE_640x480;
232
else if (xsize < 1024)
233
apple_id = APPLE_800x600;
234
else if (xsize < 1152)
235
apple_id = APPLE_1024x768;
236
else if (xsize < 1280) {
238
apple_id = APPLE_1152x768;
240
apple_id = APPLE_1152x900;
242
else if (xsize < 1600)
243
apple_id = APPLE_1280x1024;
245
apple_id = APPLE_1600x1200;
249
// Set parameters to specified Apple mode
250
static void set_apple_resolution(int apple_id, int &xsize, int &ysize)
273
case APPLE_1280x1024:
277
case APPLE_1600x1200:
286
// Match Apple mode matching best specified dimensions
287
static int match_apple_resolution(int &xsize, int &ysize)
289
int apple_id = find_apple_resolution(xsize, ysize);
290
set_apple_resolution(apple_id, xsize, ysize);
292
if (xsize == 640 && ysize == 480)
293
return APPLE_640x480;
294
if (xsize == 800 && ysize == 600)
295
return APPLE_800x600;
296
if (xsize == 1024 && ysize == 768)
297
return APPLE_1024x768;
298
if (xsize == 1152 && ysize == 768)
299
return APPLE_1152x768;
300
if (xsize == 1152 && ysize == 900)
301
return APPLE_1152x900;
302
if (xsize == 1280 && ysize == 1024)
303
return APPLE_1280x1024;
304
if (xsize == 1600 && ysize == 1200)
305
return APPLE_1600x1200;
294
309
// Display error alert
395
410
return (video_depth <= VIDEO_DEPTH_8BIT) ? 8 : mac_depth_of_video_depth(video_depth);
413
// Get screen dimensions
414
static void sdl_display_dimensions(int &width, int &height)
416
static int max_width, max_height;
417
if (max_width == 0 && max_height == 0) {
418
max_width = 640 ; max_height = 480;
419
SDL_Rect **modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
420
if (modes && modes != (SDL_Rect **)-1) {
421
// It turns out that on some implementations, and contrary to the documentation,
422
// the returned list is not sorted from largest to smallest (e.g. Windows)
423
for (int i = 0; modes[i] != NULL; i++) {
424
const int w = modes[i]->w;
425
const int h = modes[i]->h;
426
if (w > max_width && h > max_height) {
437
static inline int sdl_display_width(void)
440
sdl_display_dimensions(width, height);
444
static inline int sdl_display_height(void)
447
sdl_display_dimensions(width, height);
398
451
// Check wether specified mode is available
399
static bool has_mode(int type, int width, int height)
452
static bool has_mode(int type, int width, int height, int depth)
401
454
#ifdef SHEEPSHAVER
402
// Filter out Classic resolutiosn
455
// Filter out Classic resolutions
403
456
if (width == 512 && height == 384)
406
// "screen" prefs items always succeeds
407
if (PrefsFindString("screen"))
410
// Read window & screen modes prefs
411
static uint32 window_modes = 0;
412
static uint32 screen_modes = 0;
413
if (window_modes == 0 || screen_modes == 0) {
414
window_modes = PrefsFindInt32("windowmodes");
415
screen_modes = PrefsFindInt32("screenmodes");
416
if (window_modes == 0 || screen_modes == 0)
417
window_modes |= 3; // Allow at least 640x480 and 800x600 window modes
423
test_modes = window_modes;
426
test_modes = screen_modes;
434
switch (find_apple_resolution(width, height)) {
435
case APPLE_640x480: apple_mask = 0x01; break;
436
case APPLE_800x600: apple_mask = 0x02; break;
437
case APPLE_1024x768: apple_mask = 0x04; break;
438
case APPLE_1152x768: apple_mask = 0x40; break;
439
case APPLE_1152x900: apple_mask = 0x08; break;
440
case APPLE_1280x1024: apple_mask = 0x10; break;
441
case APPLE_1600x1200: apple_mask = 0x20; break;
442
default: apple_mask = 0x00; break;
444
return (test_modes & apple_mask);
460
// Filter out out-of-bounds resolutions
461
if (width > sdl_display_width() || height > sdl_display_height())
464
// Rely on SDL capabilities
465
return SDL_VideoModeOK(width, height,
466
sdl_depth_of_video_depth(depth),
467
SDL_HWSURFACE | (type == DISPLAY_SCREEN ? SDL_FULLSCREEN : 0));
449
470
// Add mode to list of supported modes
450
471
static void add_mode(int type, int width, int height, int resolution_id, int bytes_per_row, int depth)
452
473
// Filter out unsupported modes
453
if (!has_mode(type, width, height))
474
if (!has_mode(type, width, height, depth))
456
477
// Fill in VideoMode entry
458
479
#ifdef SHEEPSHAVER
459
// Recalculate dimensions to fit Apple modes
460
resolution_id = match_apple_resolution(width, height);
480
resolution_id = find_apple_resolution(width, height);
461
481
mode.viType = type;
463
483
VIDEO_MODE_X = width;
468
488
VideoModes.push_back(mode);
471
// Add standard list of windowed modes for given color depth
472
static void add_window_modes(int depth)
474
video_depth vdepth = (video_depth)depth;
475
add_mode(DISPLAY_WINDOW, 512, 384, 0x80, TrivialBytesPerRow(512, vdepth), depth);
476
add_mode(DISPLAY_WINDOW, 640, 480, 0x81, TrivialBytesPerRow(640, vdepth), depth);
477
add_mode(DISPLAY_WINDOW, 800, 600, 0x82, TrivialBytesPerRow(800, vdepth), depth);
478
add_mode(DISPLAY_WINDOW, 1024, 768, 0x83, TrivialBytesPerRow(1024, vdepth), depth);
479
add_mode(DISPLAY_WINDOW, 1152, 870, 0x84, TrivialBytesPerRow(1152, vdepth), depth);
480
add_mode(DISPLAY_WINDOW, 1280, 1024, 0x85, TrivialBytesPerRow(1280, vdepth), depth);
481
add_mode(DISPLAY_WINDOW, 1600, 1200, 0x86, TrivialBytesPerRow(1600, vdepth), depth);
484
491
// Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac)
485
492
static void set_mac_frame_buffer(SDL_monitor_desc &monitor, int depth, bool native_byte_order)
524
531
return (vi && vi->wm_available ? SDL_WM_GrabInput(mode) : SDL_GRAB_OFF);
534
// Migrate preferences items (XXX to be handled in MigratePrefs())
535
static void migrate_screen_prefs(void)
538
// Look-up priorities are: "screen", "screenmodes", "windowmodes".
539
if (PrefsFindString("screen"))
542
uint32 window_modes = PrefsFindInt32("windowmodes");
543
uint32 screen_modes = PrefsFindInt32("screenmodes");
544
int width = 0, height = 0;
546
static const struct {
561
for (int i = 0; modes[i].id != 0; i++) {
562
if (screen_modes & modes[i].id) {
563
if (width < modes[i].width && height < modes[i].height) {
564
width = modes[i].width;
565
height = modes[i].height;
570
if (window_modes & 1)
571
width = 640, height = 480;
572
if (window_modes & 2)
573
width = 800, height = 600;
575
if (width && height) {
577
sprintf(str, "%s/%d/%d", screen_modes ? "dga" : "win", width, height);
578
PrefsReplaceString("screen", str);
529
585
* Display "driver" classes
1077
1143
else if (sscanf(mode_str, "dga/%d/%d", &default_width, &default_height) == 2)
1078
1144
display_type = DISPLAY_SCREEN;
1080
int max_width = 640, max_height = 480;
1081
SDL_Rect **modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
1082
if (modes && modes != (SDL_Rect **)-1) {
1083
// It turns out that on some implementations, and contrary to the documentation,
1084
// the returned list is not sorted from largest to smallest (e.g. Windows)
1085
for (int i = 0; modes[i] != NULL; i++) {
1086
const int w = modes[i]->w;
1087
const int h = modes[i]->h;
1088
if (w > max_width && h > max_height) {
1093
if (default_width > max_width)
1094
default_width = max_width;
1095
if (default_height > max_height)
1096
default_height = max_height;
1098
1146
if (default_width <= 0)
1099
default_width = max_width;
1147
default_width = sdl_display_width();
1148
else if (default_width > sdl_display_width())
1149
default_width = sdl_display_width();
1100
1150
if (default_height <= 0)
1101
default_height = max_height;
1151
default_height = sdl_display_height();
1152
else if (default_height > sdl_display_height())
1153
default_height = sdl_display_height();
1103
1155
// Mac screen depth follows X depth
1104
1156
screen_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
1173
// Initialize list of video modes to try
1184
{ 1024, 768, 0x83 },
1185
{ 1152, 870, 0x84 },
1186
{ 1280, 1024, 0x85 },
1187
{ 1600, 1200, 0x86 },
1190
video_modes[0].w = default_width;
1191
video_modes[0].h = default_height;
1121
1193
// Construct list of supported modes
1122
1194
if (display_type == DISPLAY_WINDOW) {
1124
1196
add_mode(display_type, 512, 342, 0x80, 64, VIDEO_DEPTH_1BIT);
1126
for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++) {
1127
int bpp = sdl_depth_of_video_depth(d);
1128
if (SDL_VideoModeOK(max_width, max_height, bpp, SDL_HWSURFACE))
1129
add_window_modes(video_depth(d));
1198
for (int i = 0; video_modes[i].w != 0; i++) {
1199
const int w = video_modes[i].w;
1200
const int h = video_modes[i].h;
1201
if (i > 0 && (w >= default_width || h >= default_height))
1203
for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++)
1204
add_mode(display_type, w, h, video_modes[i].resolution_id, TrivialBytesPerRow(w, (video_depth)d), d);
1132
1207
} else if (display_type == DISPLAY_SCREEN) {
1142
{ 1024, 768, 0x83 },
1143
{ 1152, 870, 0x84 },
1144
{ 1280, 1024, 0x85 },
1145
{ 1600, 1200, 0x86 },
1148
video_modes[0].w = default_width;
1149
video_modes[0].h = default_height;
1151
1208
for (int i = 0; video_modes[i].w != 0; i++) {
1152
1209
const int w = video_modes[i].w;
1153
1210
const int h = video_modes[i].h;
1154
1211
if (i > 0 && (w >= default_width || h >= default_height))
1213
if (w == 512 && h == 384)
1156
1215
#ifdef ENABLE_VOSF
1157
for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++) {
1158
int bpp = sdl_depth_of_video_depth(d);
1159
if (SDL_VideoModeOK(w, h, bpp, SDL_HWSURFACE | SDL_FULLSCREEN))
1160
add_mode(display_type, w, h, video_modes[i].resolution_id, TrivialBytesPerRow(w, (video_depth)d), d);
1216
for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++)
1217
add_mode(display_type, w, h, video_modes[i].resolution_id, TrivialBytesPerRow(w, (video_depth)d), d);
1163
1219
add_mode(display_type, w, h, video_modes[i].resolution_id, TrivialBytesPerRow(w, (video_depth)default_depth), default_depth);
1990
// Static display update (fixed frame rate, bounding boxes based)
1991
// XXX use NQD bounding boxes to help detect dirty areas?
1992
static void update_display_static_bbox(driver_window *drv)
1994
const VIDEO_MODE &mode = drv->mode;
1996
// Allocate bounding boxes for SDL_UpdateRects()
1997
const int N_PIXELS = 64;
1998
const int n_x_boxes = (VIDEO_MODE_X + N_PIXELS - 1) / N_PIXELS;
1999
const int n_y_boxes = (VIDEO_MODE_Y + N_PIXELS - 1) / N_PIXELS;
2000
SDL_Rect *boxes = (SDL_Rect *)alloca(sizeof(SDL_Rect) * n_x_boxes * n_y_boxes);
2003
// Lock surface, if required
2004
if (SDL_MUSTLOCK(drv->s))
2005
SDL_LockSurface(drv->s);
2007
// Update the surface from Mac screen
2008
const int bytes_per_row = VIDEO_MODE_ROW_BYTES;
2009
const int bytes_per_pixel = bytes_per_row / VIDEO_MODE_X;
2011
for (y = 0; y < VIDEO_MODE_Y; y += N_PIXELS) {
2013
if (h > VIDEO_MODE_Y - y)
2014
h = VIDEO_MODE_Y - y;
2015
for (x = 0; x < VIDEO_MODE_X; x += N_PIXELS) {
2017
if (w > VIDEO_MODE_X - x)
2018
w = VIDEO_MODE_X - x;
2019
const int xs = w * bytes_per_pixel;
2020
const int xb = x * bytes_per_pixel;
2022
for (int j = y; j < (y + h); j++) {
2023
const int yb = j * bytes_per_row;
2024
if (memcmp(&the_buffer[yb + xb], &the_buffer_copy[yb + xb], xs) != 0) {
2025
memcpy(&the_buffer_copy[yb + xb], &the_buffer[yb + xb], xs);
2026
Screen_blit((uint8 *)drv->s->pixels + yb + xb, the_buffer + yb + xb, xs);
2031
boxes[nr_boxes].x = x;
2032
boxes[nr_boxes].y = y;
2033
boxes[nr_boxes].w = w;
2034
boxes[nr_boxes].h = h;
2040
// Unlock surface, if required
2041
if (SDL_MUSTLOCK(drv->s))
2042
SDL_UnlockSurface(drv->s);
2046
SDL_UpdateRects(drv->s, nr_boxes, boxes);
1925
2050
// We suggest the compiler to inline the next two functions so that it
1926
2051
// may specialise the code according to the current screen depth and
2057
2186
// Set new cursor image if it was changed
2058
2187
if (cursor_changed && sdl_cursor) {
2059
2188
cursor_changed = false;
2060
2190
SDL_FreeCursor(sdl_cursor);
2061
2191
sdl_cursor = SDL_CreateCursor(MacCursor + 4, MacCursor + 36, 16, 16, MacCursor[2], MacCursor[3]);
2063
2193
SDL_SetCursor(sdl_cursor);
2195
// XXX Windows apparently needs an extra mouse event to
2196
// make the new cursor image visible
2197
int visible = SDL_ShowCursor(-1);
2200
SDL_GetMouseState(&x, &y);
2201
SDL_WarpMouse(x, y);
2266
* Record dirty area from NQD
2270
void video_set_dirty_area(int x, int y, int w, int h)
2272
const VIDEO_MODE &mode = drv->mode;
2273
const int screen_width = VIDEO_MODE_X;
2274
const int screen_height = VIDEO_MODE_Y;
2275
const int bytes_per_row = VIDEO_MODE_ROW_BYTES;
2279
vosf_set_dirty_area(x, y, w, h, screen_width, screen_height, bytes_per_row);
2284
// XXX handle dirty bounding boxes for non-VOSF modes