35 |
|
* - Events processing is bound to the general emulation thread as SDL requires |
36 |
|
* to PumpEvents() within the same thread as the one that called SetVideoMode(). |
37 |
|
* Besides, there can't seem to be a way to call SetVideoMode() from a child thread. |
38 |
+ |
* - Refresh performance is still slow. Use SDL_CreateRGBSurface()? |
39 |
+ |
* - Backport hw cursor acceleration to Basilisk II? |
40 |
+ |
* - Move generic Native QuickDraw acceleration routines to gfxaccel.cpp |
41 |
|
*/ |
42 |
|
|
43 |
|
#include "sysdeps.h" |
99 |
|
static SDL_Thread *redraw_thread = NULL; // Redraw thread |
100 |
|
|
101 |
|
#ifdef ENABLE_VOSF |
102 |
< |
static bool use_vosf = true; // Flag: VOSF enabled |
102 |
> |
static bool use_vosf = false; // Flag: VOSF enabled |
103 |
|
#else |
104 |
|
static const bool use_vosf = false; // VOSF not possible |
105 |
|
#endif |
117 |
|
|
118 |
|
// SDL variables |
119 |
|
static int screen_depth; // Depth of current screen |
120 |
+ |
static SDL_Cursor *sdl_cursor; // Copy of Mac cursor |
121 |
+ |
static volatile bool cursor_changed = false; // Flag: cursor changed, redraw_func must update the cursor |
122 |
|
static SDL_Color sdl_palette[256]; // Color palette to be used as CLUT and gamma table |
123 |
|
static bool sdl_palette_changed = false; // Flag: Palette changed, redraw thread must set new colors |
124 |
|
static const int sdl_eventmask = SDL_MOUSEBUTTONDOWNMASK | SDL_MOUSEBUTTONUPMASK | SDL_MOUSEMOTIONMASK | SDL_KEYUPMASK | SDL_KEYDOWNMASK | SDL_VIDEOEXPOSEMASK | SDL_QUITMASK; |
260 |
|
{ |
261 |
|
ErrorAlert(GetString(error)); |
262 |
|
} |
263 |
+ |
|
264 |
+ |
// Display warning alert |
265 |
+ |
static void WarningAlert(int warning) |
266 |
+ |
{ |
267 |
+ |
WarningAlert(GetString(warning)); |
268 |
+ |
} |
269 |
|
#endif |
270 |
|
|
271 |
|
|
353 |
|
return depth; |
354 |
|
} |
355 |
|
|
356 |
< |
// Add mode to list of supported modes |
357 |
< |
static void add_mode(int type, int width, int height, int resolution_id, int bytes_per_row, int depth) |
356 |
> |
// Check wether specified mode is available |
357 |
> |
static bool has_mode(int type, int width, int height) |
358 |
|
{ |
359 |
< |
VIDEO_MODE mode; |
359 |
> |
// FIXME: no fullscreen support yet |
360 |
> |
if (type == DISPLAY_SCREEN) |
361 |
> |
return false; |
362 |
> |
|
363 |
|
#ifdef SHEEPSHAVER |
364 |
< |
// Don't add 512x384 modes |
364 |
> |
// Filter out Classic resolutiosn |
365 |
|
if (width == 512 && height == 384) |
366 |
+ |
return false; |
367 |
+ |
|
368 |
+ |
// Read window modes prefs |
369 |
+ |
static uint32 window_modes = 0; |
370 |
+ |
static uint32 screen_modes = 0; |
371 |
+ |
if (window_modes == 0 || screen_modes == 0) { |
372 |
+ |
window_modes = PrefsFindInt32("windowmodes"); |
373 |
+ |
screen_modes = PrefsFindInt32("screenmodes"); |
374 |
+ |
if (window_modes == 0 || screen_modes == 0) |
375 |
+ |
window_modes |= 3; // Allow at least 640x480 and 800x600 window modes |
376 |
+ |
} |
377 |
+ |
|
378 |
+ |
if (type == DISPLAY_WINDOW) { |
379 |
+ |
int apple_mask, apple_id = find_apple_resolution(width, height); |
380 |
+ |
switch (apple_id) { |
381 |
+ |
case APPLE_640x480: apple_mask = 0x01; break; |
382 |
+ |
case APPLE_800x600: apple_mask = 0x02; break; |
383 |
+ |
case APPLE_1024x768: apple_mask = 0x04; break; |
384 |
+ |
case APPLE_1152x768: apple_mask = 0x40; break; |
385 |
+ |
case APPLE_1152x900: apple_mask = 0x08; break; |
386 |
+ |
case APPLE_1280x1024: apple_mask = 0x10; break; |
387 |
+ |
case APPLE_1600x1200: apple_mask = 0x20; break; |
388 |
+ |
default: apple_mask = 0x00; break; |
389 |
+ |
} |
390 |
+ |
return (window_modes & apple_mask); |
391 |
+ |
} |
392 |
+ |
#else |
393 |
+ |
return true; |
394 |
+ |
#endif |
395 |
+ |
return false; |
396 |
+ |
} |
397 |
+ |
|
398 |
+ |
// Add mode to list of supported modes |
399 |
+ |
static void add_mode(int type, int width, int height, int resolution_id, int bytes_per_row, int depth) |
400 |
+ |
{ |
401 |
+ |
// Filter out unsupported modes |
402 |
+ |
if (!has_mode(type, width, height)) |
403 |
|
return; |
404 |
|
|
405 |
+ |
// Fill in VideoMode entry |
406 |
+ |
VIDEO_MODE mode; |
407 |
+ |
#ifdef SHEEPSHAVER |
408 |
|
// Recalculate dimensions to fit Apple modes |
409 |
|
resolution_id = match_apple_resolution(width, height); |
410 |
|
mode.viType = type; |
630 |
|
the_buffer = (uint8 *)vm_acquire(the_buffer_size); |
631 |
|
the_buffer_copy = (uint8 *)malloc(the_buffer_size); |
632 |
|
D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer)); |
633 |
+ |
|
634 |
+ |
// Check whether we can initialize the VOSF subsystem and it's profitable |
635 |
+ |
if (!video_vosf_init(m)) { |
636 |
+ |
WarningAlert(STR_VOSF_INIT_ERR); |
637 |
+ |
use_vosf = false; |
638 |
+ |
} |
639 |
+ |
else if (!video_vosf_profitable()) { |
640 |
+ |
video_vosf_exit(); |
641 |
+ |
printf("VOSF acceleration is not profitable on this platform, disabling it\n"); |
642 |
+ |
use_vosf = false; |
643 |
+ |
} |
644 |
+ |
if (!use_vosf) { |
645 |
+ |
free(the_buffer_copy); |
646 |
+ |
vm_release(the_buffer, the_buffer_size); |
647 |
+ |
the_host_buffer = NULL; |
648 |
+ |
} |
649 |
+ |
#endif |
650 |
+ |
if (!use_vosf) { |
651 |
+ |
// Allocate memory for frame buffer |
652 |
+ |
the_buffer_size = (aligned_height + 2) * s->pitch; |
653 |
+ |
the_buffer_copy = (uint8 *)calloc(1, the_buffer_size); |
654 |
+ |
the_buffer = (uint8 *)calloc(1, the_buffer_size); |
655 |
+ |
D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy)); |
656 |
+ |
} |
657 |
+ |
|
658 |
+ |
#ifdef SHEEPSHAVER |
659 |
+ |
// Create cursor |
660 |
+ |
if ((sdl_cursor = SDL_CreateCursor(MacCursor + 4, MacCursor + 36, 16, 16, 0, 0)) != NULL) { |
661 |
+ |
SDL_SetCursor(sdl_cursor); |
662 |
+ |
cursor_changed = false; |
663 |
+ |
} |
664 |
|
#else |
665 |
< |
// Allocate memory for frame buffer |
666 |
< |
the_buffer_size = (aligned_height + 2) * s->pitch; |
582 |
< |
the_buffer_copy = (uint8 *)calloc(1, the_buffer_size); |
583 |
< |
the_buffer = (uint8 *)calloc(1, the_buffer_size); |
584 |
< |
D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy)); |
665 |
> |
// Hide cursor |
666 |
> |
SDL_ShowCursor(0); |
667 |
|
#endif |
668 |
|
|
669 |
|
// Set window name/class |
670 |
|
set_window_name(STR_WINDOW_TITLE); |
671 |
|
|
590 |
– |
// Hide cursor |
591 |
– |
SDL_ShowCursor(0); |
592 |
– |
|
672 |
|
// Init blitting routines |
673 |
|
SDL_PixelFormat *f = s->format; |
674 |
|
VisualFormat visualFormat; |
787 |
|
|
788 |
|
if (video_driver_found) { |
789 |
|
// Skip aliases |
790 |
< |
static const char alias_str[] = "alias"; |
791 |
< |
if (strncmp(line, alias_str, sizeof(alias_str) - 1) == 0) |
790 |
> |
static const char sdl_str[] = "sdl"; |
791 |
> |
if (strncmp(line, sdl_str, sizeof(sdl_str) - 1) == 0) |
792 |
|
continue; |
793 |
|
|
794 |
|
// Read keycode |
799 |
|
break; |
800 |
|
} else { |
801 |
|
// Search for SDL video driver string |
802 |
< |
static const char alias_sdl_str[] = "alias SDL"; |
803 |
< |
if (strncmp(line, alias_sdl_str, sizeof(alias_sdl_str) - 1) == 0) { |
804 |
< |
char *p = line + sizeof(alias_sdl_str); |
802 |
> |
static const char sdl_str[] = "sdl"; |
803 |
> |
if (strncmp(line, sdl_str, sizeof(sdl_str) - 1) == 0) { |
804 |
> |
char *p = line + sizeof(sdl_str); |
805 |
|
if (strstr(video_driver, p) == video_driver) |
806 |
|
video_driver_found = true; |
807 |
|
} |
827 |
|
{ |
828 |
|
D(bug("video_open()\n")); |
829 |
|
const VIDEO_MODE &mode = get_current_mode(); |
830 |
+ |
#if DEBUG |
831 |
+ |
D(bug("Current video mode:\n")); |
832 |
+ |
D(bug(" %dx%d (ID %02x), %d bpp\n", VIDEO_MODE_X, VIDEO_MODE_Y, VIDEO_MODE_RESOLUTION, 1 << (VIDEO_MODE_DEPTH & 0x0f))); |
833 |
+ |
#endif |
834 |
|
|
835 |
|
// Create display driver object of requested type |
836 |
|
switch (display_type) { |
846 |
|
return false; |
847 |
|
} |
848 |
|
|
766 |
– |
#ifdef ENABLE_VOSF |
767 |
– |
if (use_vosf) { |
768 |
– |
// Initialize the VOSF system |
769 |
– |
if (!video_vosf_init(*this)) { |
770 |
– |
ErrorAlert(STR_VOSF_INIT_ERR); |
771 |
– |
return false; |
772 |
– |
} |
773 |
– |
} |
774 |
– |
#endif |
775 |
– |
|
849 |
|
// Initialize VideoRefresh function |
850 |
|
VideoRefreshInit(); |
851 |
|
|
893 |
|
mouse_wheel_lines = PrefsFindInt32("mousewheellines"); |
894 |
|
|
895 |
|
// Get screen mode from preferences |
896 |
< |
const char *mode_str; |
896 |
> |
const char *mode_str = NULL; |
897 |
> |
#ifndef SHEEPSHAVER |
898 |
|
if (classic_mode) |
899 |
|
mode_str = "win/512/342"; |
900 |
|
else |
901 |
|
mode_str = PrefsFindString("screen"); |
902 |
+ |
#endif |
903 |
|
|
904 |
|
// Determine display type and default dimensions |
905 |
|
int default_width, default_height; |
917 |
|
display_type = DISPLAY_WINDOW; |
918 |
|
} |
919 |
|
int max_width = 640, max_height = 480; |
920 |
< |
if (display_type == DISPLAY_SCREEN) { |
921 |
< |
SDL_Rect **modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE); |
922 |
< |
if (modes && modes != (SDL_Rect **)-1) { |
923 |
< |
max_width = modes[0]->w; |
924 |
< |
max_height = modes[0]->h; |
925 |
< |
} |
920 |
> |
SDL_Rect **modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE); |
921 |
> |
if (modes && modes != (SDL_Rect **)-1) { |
922 |
> |
max_width = modes[0]->w; |
923 |
> |
max_height = modes[0]->h; |
924 |
> |
if (default_width > max_width) |
925 |
> |
default_width = max_width; |
926 |
> |
if (default_height > max_height) |
927 |
> |
default_height = max_height; |
928 |
|
} |
929 |
|
if (default_width <= 0) |
930 |
|
default_width = max_width; |
991 |
|
} |
992 |
|
|
993 |
|
#ifdef SHEEPSHAVER |
994 |
< |
for (int i = 0; i < VideoModes.size(); ++i) |
994 |
> |
for (int i = 0; i < VideoModes.size(); i++) |
995 |
|
VModes[i] = VideoModes[i]; |
996 |
< |
|
997 |
< |
const VIDEO_MODE & mode = VideoModes[cur_mode]; |
998 |
< |
D(bug("Current video mode\n")); |
999 |
< |
D(bug(" %dx%d (ID %02x), %d bpp\n", VIDEO_MODE_X, VIDEO_MODE_Y, VIDEO_MODE_RESOLUTION, 1 << (VIDEO_MODE_DEPTH - 0x80))); |
996 |
> |
VideoInfo *p = &VModes[VideoModes.size()]; |
997 |
> |
p->viType = DIS_INVALID; // End marker |
998 |
> |
p->viRowBytes = 0; |
999 |
> |
p->viXsize = p->viYsize = 0; |
1000 |
> |
p->viAppleMode = 0; |
1001 |
> |
p->viAppleID = 0; |
1002 |
|
#endif |
1003 |
|
|
1004 |
|
#if DEBUG |
1172 |
|
} |
1173 |
|
|
1174 |
|
#ifdef ENABLE_VOSF |
1175 |
< |
// We have to redraw everything because the interpretation of pixel values changed |
1176 |
< |
LOCK_VOSF; |
1177 |
< |
PFLAG_SET_ALL; |
1178 |
< |
UNLOCK_VOSF; |
1179 |
< |
memset(the_buffer_copy, 0, VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y); |
1175 |
> |
if (use_vosf) { |
1176 |
> |
// We have to redraw everything because the interpretation of pixel values changed |
1177 |
> |
LOCK_VOSF; |
1178 |
> |
PFLAG_SET_ALL; |
1179 |
> |
UNLOCK_VOSF; |
1180 |
> |
memset(the_buffer_copy, 0, VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y); |
1181 |
> |
} |
1182 |
|
#endif |
1183 |
|
} |
1184 |
|
|
1249 |
|
#ifdef SHEEPSHAVER |
1250 |
|
bool video_can_change_cursor(void) |
1251 |
|
{ |
1252 |
< |
// return hw_mac_cursor_accl && (display_type != DISPLAY_SCREEN); |
1172 |
< |
return false; |
1252 |
> |
return (display_type == DISPLAY_WINDOW); |
1253 |
|
} |
1254 |
|
#endif |
1255 |
|
|
1261 |
|
#ifdef SHEEPSHAVER |
1262 |
|
void video_set_cursor(void) |
1263 |
|
{ |
1264 |
< |
// cursor_changed = true; |
1264 |
> |
cursor_changed = true; |
1265 |
|
} |
1266 |
|
#endif |
1267 |
|
|
1629 |
|
|
1630 |
|
|
1631 |
|
/* |
1632 |
< |
* Translate key event to Mac keycode, returns -1 if no keycode was found |
1553 |
< |
* and -2 if the key was recognized as a hotkey |
1632 |
> |
* Keyboard-related utilify functions |
1633 |
|
*/ |
1634 |
|
|
1635 |
+ |
static bool is_modifier_key(SDL_KeyboardEvent const & e) |
1636 |
+ |
{ |
1637 |
+ |
switch (e.keysym.sym) { |
1638 |
+ |
case SDLK_NUMLOCK: |
1639 |
+ |
case SDLK_CAPSLOCK: |
1640 |
+ |
case SDLK_SCROLLOCK: |
1641 |
+ |
case SDLK_RSHIFT: |
1642 |
+ |
case SDLK_LSHIFT: |
1643 |
+ |
case SDLK_RCTRL: |
1644 |
+ |
case SDLK_LCTRL: |
1645 |
+ |
case SDLK_RALT: |
1646 |
+ |
case SDLK_LALT: |
1647 |
+ |
case SDLK_RMETA: |
1648 |
+ |
case SDLK_LMETA: |
1649 |
+ |
case SDLK_LSUPER: |
1650 |
+ |
case SDLK_RSUPER: |
1651 |
+ |
case SDLK_MODE: |
1652 |
+ |
case SDLK_COMPOSE: |
1653 |
+ |
return true; |
1654 |
+ |
} |
1655 |
+ |
return false; |
1656 |
+ |
} |
1657 |
+ |
|
1658 |
|
static bool is_ctrl_down(SDL_keysym const & ks) |
1659 |
|
{ |
1660 |
|
return ctrl_down || (ks.mod & KMOD_CTRL); |
1661 |
|
} |
1662 |
|
|
1663 |
+ |
|
1664 |
+ |
/* |
1665 |
+ |
* Translate key event to Mac keycode, returns -1 if no keycode was found |
1666 |
+ |
* and -2 if the key was recognized as a hotkey |
1667 |
+ |
*/ |
1668 |
+ |
|
1669 |
|
static int kc_decode(SDL_keysym const & ks, bool key_down) |
1670 |
|
{ |
1671 |
|
switch (ks.sym) { |
1735 |
|
case SDLK_RCTRL: return 0x36; |
1736 |
|
case SDLK_LSHIFT: return 0x38; |
1737 |
|
case SDLK_RSHIFT: return 0x38; |
1738 |
+ |
#if (defined(__APPLE__) && defined(__MACH__)) |
1739 |
+ |
case SDLK_LALT: return 0x3a; |
1740 |
+ |
case SDLK_RALT: return 0x3a; |
1741 |
+ |
case SDLK_LMETA: return 0x37; |
1742 |
+ |
case SDLK_RMETA: return 0x37; |
1743 |
+ |
#else |
1744 |
|
case SDLK_LALT: return 0x37; |
1745 |
|
case SDLK_RALT: return 0x37; |
1746 |
|
case SDLK_LMETA: return 0x3a; |
1747 |
|
case SDLK_RMETA: return 0x3a; |
1748 |
+ |
#endif |
1749 |
|
case SDLK_MENU: return 0x32; |
1750 |
|
case SDLK_CAPSLOCK: return 0x39; |
1751 |
|
case SDLK_NUMLOCK: return 0x47; |
1852 |
|
// Keyboard |
1853 |
|
case SDL_KEYDOWN: { |
1854 |
|
int code = -1; |
1855 |
< |
if (use_keycodes) { |
1855 |
> |
if (use_keycodes && !is_modifier_key(event.key)) { |
1856 |
|
if (event2keycode(event.key, true) != -2) // This is called to process the hotkeys |
1857 |
|
code = keycode_table[event.key.keysym.scancode & 0xff]; |
1858 |
|
} else |
1880 |
|
} |
1881 |
|
case SDL_KEYUP: { |
1882 |
|
int code = -1; |
1883 |
< |
if (use_keycodes) { |
1883 |
> |
if (use_keycodes && !is_modifier_key(event.key)) { |
1884 |
|
if (event2keycode(event.key, false) != -2) // This is called to process the hotkeys |
1885 |
|
code = keycode_table[event.key.keysym.scancode & 0xff]; |
1886 |
|
} else |
1887 |
|
code = event2keycode(event.key, false); |
1888 |
< |
if (code >= 0 && code != 0x39) { // Don't propagate Caps Lock releases |
1889 |
< |
ADBKeyUp(code); |
1888 |
> |
if (code >= 0) { |
1889 |
> |
if (code == 0x39) { // Caps Lock released |
1890 |
> |
if (caps_on) { |
1891 |
> |
ADBKeyUp(code); |
1892 |
> |
caps_on = false; |
1893 |
> |
} else { |
1894 |
> |
ADBKeyDown(code); |
1895 |
> |
caps_on = true; |
1896 |
> |
} |
1897 |
> |
} else |
1898 |
> |
ADBKeyUp(code); |
1899 |
|
if (code == 0x36) |
1900 |
|
ctrl_down = false; |
1901 |
|
} |
2229 |
|
// Refresh display |
2230 |
|
video_refresh(); |
2231 |
|
|
2232 |
+ |
#ifdef SHEEPSHAVER |
2233 |
+ |
// Set new cursor image if it was changed |
2234 |
+ |
if (cursor_changed && sdl_cursor) { |
2235 |
+ |
cursor_changed = false; |
2236 |
+ |
SDL_FreeCursor(sdl_cursor); |
2237 |
+ |
sdl_cursor = SDL_CreateCursor(MacCursor + 4, MacCursor + 36, 16, 16, MacCursor[2], MacCursor[3]); |
2238 |
+ |
if (sdl_cursor) |
2239 |
+ |
SDL_SetCursor(sdl_cursor); |
2240 |
+ |
} |
2241 |
+ |
#endif |
2242 |
+ |
|
2243 |
|
// Set new palette if it was changed |
2244 |
|
handle_palette_changes(); |
2245 |
|
} |