These code changes were all delivered into the official CVS source tree in June 2008. --- BasiliskII/src/MacOSX/extfs_macosx.cpp.00 2008-01-01 01:40:32.000000000 -0800 +++ BasiliskII/src/MacOSX/extfs_macosx.cpp 2008-06-19 12:21:22.000000000 -0700 @@ -239,7 +239,7 @@ // The rsrc component is copied as is, if there is not enough // space to add it. In that case, open() will fail gracefully // and this is what we want. - dest[0] - '.'; + dest[0] = '.'; dest[1] = '\0'; } --- BasiliskII/src/SDL/video_sdl.cpp.00 2008-04-08 10:36:32.000000000 -0700 +++ BasiliskII/src/SDL/video_sdl.cpp 2008-06-22 16:18:22.000000000 -0700 @@ -136,7 +136,7 @@ static volatile bool cursor_changed = false; // Flag: cursor changed, redraw_func must update the cursor static SDL_Color sdl_palette[256]; // Color palette to be used as CLUT and gamma table static bool sdl_palette_changed = false; // Flag: Palette changed, redraw thread must set new colors -static const int sdl_eventmask = SDL_MOUSEBUTTONDOWNMASK | SDL_MOUSEBUTTONUPMASK | SDL_MOUSEMOTIONMASK | SDL_KEYUPMASK | SDL_KEYDOWNMASK | SDL_VIDEOEXPOSEMASK | SDL_QUITMASK; +static const int sdl_eventmask = SDL_MOUSEEVENTMASK | SDL_KEYEVENTMASK | SDL_VIDEOEXPOSEMASK | SDL_QUITMASK | SDL_ACTIVEEVENTMASK; // Mutex to protect SDL events static SDL_mutex *sdl_events_lock = NULL; @@ -1543,7 +1543,23 @@ #ifdef SHEEPSHAVER bool video_can_change_cursor(void) { - return (display_type == DISPLAY_WINDOW); + static char driver[] = "Quartz?"; + static int quartzok = -1; + + if (display_type != DISPLAY_WINDOW) + return false; + + if (quartzok < 0) { + if (SDL_VideoDriverName(driver, sizeof driver) == NULL || strncmp(driver, "Quartz", sizeof driver)) + quartzok = true; + else { + // Quartz driver bug prevents cursor changing in SDL 1.2.11 and later + const SDL_version *vp = SDL_Linked_Version(); + quartzok = SDL_VERSIONNUM(vp->major, vp->minor, vp->patch) <= SDL_VERSIONNUM(1, 2, 10); + } + } + + return quartzok; } #endif @@ -1858,6 +1874,10 @@ ADBKeyDown(0x7f); // Power key ADBKeyUp(0x7f); break; + + // Application activate/deactivate; consume the event but otherwise ignore it + case SDL_ACTIVEEVENT: + break; } } } @@ -2216,6 +2236,7 @@ SDL_FreeCursor(sdl_cursor); sdl_cursor = SDL_CreateCursor(MacCursor + 4, MacCursor + 36, 16, 16, MacCursor[2], MacCursor[3]); if (sdl_cursor) { + SDL_ShowCursor(private_data == NULL || private_data->cursorVisible); SDL_SetCursor(sdl_cursor); #ifdef WIN32 // XXX Windows apparently needs an extra mouse event to --- BasiliskII/src/cdrom.cpp.00 2008-01-01 01:40:31.000000000 -0800 +++ BasiliskII/src/cdrom.cpp 2008-06-25 09:56:40.000000000 -0700 @@ -910,6 +910,17 @@ } return noErr; } + + case 97: { // WhoIsThere + uint8 drives_present = 0; + drive_vec::iterator info, end = drives.end(); + for (info = drives.begin(); info != end; ++info) { + if (info->num <= 6) + drives_present |= 1 << info->num; + } + WriteMacInt8(pb + csParam + 1, drives_present); + return noErr; + } } // Drive valid? @@ -961,7 +972,7 @@ case 121: // Get CD features WriteMacInt16(pb + csParam, 0x0200); // 300 KB/s - WriteMacInt16(pb + csParam, 0x0300); // SCSI-2, stereo + WriteMacInt16(pb + csParam + 2, 0x0c00); // SCSI-2, stereo return noErr; default: --- BasiliskII/src/extfs.cpp.00 2008-01-01 01:40:31.000000000 -0800 +++ BasiliskII/src/extfs.cpp 2008-06-18 21:44:28.000000000 -0700 @@ -1800,7 +1800,7 @@ return fnOpnErr; // Set file position - switch (ReadMacInt16(pb + ioPosMode)) { + switch (ReadMacInt16(pb + ioPosMode) & 3) { case fsFromStart: if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0) return posErr; --- SheepShaver/src/Unix/main_unix.cpp.00 2008-01-01 01:47:38.000000000 -0800 +++ SheepShaver/src/Unix/main_unix.cpp 2008-06-22 12:28:33.000000000 -0700 @@ -372,8 +372,11 @@ bool memory_mapped_from_zero; #ifdef USE_SDL_VIDEO - // don't let SDL block the screensaver - setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1); + // Don't let SDL block the screensaver + putenv("SDL_VIDEO_ALLOW_SCREENSAVER=1"); + + // Make SDL pass through command-clicks and option-clicks unaltered + putenv("SDL_HAS3BUTTONMOUSE=1"); #endif // Initialize variables --- SheepShaver/src/Unix/sysdeps.h.00 2008-01-01 01:47:39.000000000 -0800 +++ SheepShaver/src/Unix/sysdeps.h 2008-06-19 16:25:02.000000000 -0700 @@ -108,7 +108,7 @@ #define PPC_DECODE_CACHE 1 #define PPC_FLIGHT_RECORDER 1 #define PPC_PROFILE_COMPILE_TIME 0 -#define PPC_PROFILE_GENERIC_CALLS 1 +#define PPC_PROFILE_GENERIC_CALLS 0 #define PPC_PROFILE_REGS_USE 0 #define KPX_MAX_CPUS 1 #if ENABLE_DYNGEN --- SheepShaver/src/include/video.h.00 2008-01-01 01:47:39.000000000 -0800 +++ SheepShaver/src/include/video.h 2008-05-19 18:18:02.000000000 -0700 @@ -118,10 +118,14 @@ uint32 maxGammaTableSize; // Biggest gamma table allocated uint32 saveVidParms; bool luminanceMapping; // Luminance mapping on/off - int32 cursorX; // Hardware cursor state. Unused, but must be remembered + bool cursorHardware; // True if using hardware cursor + int32 cursorX; // Hardware cursor state int32 cursorY; uint32 cursorVisible; uint32 cursorSet; + bool cursorHotFlag; + uint8 cursorHotX; + uint8 cursorHotY; uint32 vslServiceID; // VSL interrupt service ID bool interruptsEnabled; // VBL interrupts on/off uint32 regEntryID; // Mac address of the service owner --- SheepShaver/src/video.cpp.00 2008-04-07 00:13:17.000000000 -0700 +++ SheepShaver/src/video.cpp 2008-06-22 16:24:26.000000000 -0700 @@ -21,7 +21,6 @@ /* * TODO * - check for supported modes ??? - * - window mode "hardware" cursor hotspot */ #include @@ -143,6 +142,17 @@ /* + * Determine whether we should use the hardware or software cursor, and return true for the former, false for the latter. + * Currently we use the hardware cursor if we can, but perhaps this can be made a preference someday. + */ + +static bool UseHardwareCursor(void) +{ + return video_can_change_cursor(); +} + + +/* * Video driver open routine */ @@ -157,10 +167,14 @@ csSave->savePage = 0; csSave->saveVidParms = 0; // Add the right table csSave->luminanceMapping = false; + csSave->cursorHardware = UseHardwareCursor(); csSave->cursorX = 0; csSave->cursorY = 0; csSave->cursorVisible = 0; csSave->cursorSet = 0; + csSave->cursorHotFlag = false; + csSave->cursorHotX = 0; + csSave->cursorHotY = 0; // Find and set default gamma table csSave->gammaTable = 0; @@ -416,35 +430,44 @@ case cscSetHardwareCursor: { // D(bug("SetHardwareCursor\n")); + + if (!csSave->cursorHardware) + return controlErr; + csSave->cursorSet = false; bool changed = false; - // Get cursor data even on a screen, to set the right cursor image when switching back to a window // Image uint32 cursor = ReadMacInt32(param); // Pointer to CursorImage uint32 pmhandle = ReadMacInt32(cursor + ciCursorPixMap); if (pmhandle == 0 || ReadMacInt32(pmhandle) == 0) return controlErr; uint32 pixmap = ReadMacInt32(pmhandle); - if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) { - memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32); - changed = true; - } + + // XXX: only certain image formats are handled properly at the moment + uint16 rowBytes = ReadMacInt16(pixmap + 4) & 0x7FFF; + if (rowBytes != 2) + return controlErr; // Mask uint32 bmhandle = ReadMacInt32(cursor + ciCursorBitMask); if (bmhandle == 0 || ReadMacInt32(bmhandle) == 0) return controlErr; uint32 bitmap = ReadMacInt32(bmhandle); + + // Get cursor data even on a screen, to set the right cursor image when switching back to a window. + // Hotspot is stale, but will be fixed by the next call to DrawHardwareCursor, which is likely to + // occur immediately hereafter. + + if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) { + memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32); + changed = true; + } if (memcmp(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32)) { memcpy(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32); changed = true; } - // Hotspot (!! this doesn't work) - MacCursor[2] = ReadMacInt8(0x885); - MacCursor[3] = ReadMacInt8(0x887); - // Set new cursor image if (!video_can_change_cursor()) return controlErr; @@ -452,15 +475,78 @@ video_set_cursor(); csSave->cursorSet = true; + csSave->cursorHotFlag = true; return noErr; } - case cscDrawHardwareCursor: + case cscDrawHardwareCursor: { // D(bug("DrawHardwareCursor\n")); + + if (!csSave->cursorHardware) + return controlErr; + + int32 oldX = csSave->cursorX; + int32 oldY = csSave->cursorY; + uint32 oldVisible = csSave->cursorVisible; + csSave->cursorX = ReadMacInt32(param + csCursorX); csSave->cursorY = ReadMacInt32(param + csCursorY); csSave->cursorVisible = ReadMacInt32(param + csCursorVisible); + bool changed = (csSave->cursorVisible != oldVisible); + + // If this is the first DrawHardwareCursor call since the cursor was last set (via SetHardwareCursor), + // attempt to set an appropriate cursor hotspot. SetHardwareCursor itself does not know what the + // hotspot should be; it knows only the cursor image and mask. The hotspot is known only to the caller, + // and we have to try to infer it here. The usual sequence of calls when changing the cursor is: + // + // DrawHardwareCursor with (oldX, oldY, invisible) + // SetHardwareCursor with (cursor) + // DrawHardwareCursor with (newX, newY, visible) + // + // The key thing to note is that the sequence is intended not to change the current screen pixel location + // indicated by the hotspot. Thus, the difference between (newX, newY) and (oldX, oldY) reflects precisely + // the difference between the old cursor hotspot and the new one. For example, if you change from a + // cursor whose hotspot is (1, 1) to one whose hotspot is (7, 4), then you must adjust the cursor position + // by (-6, -3) in order for the same screen pixel to remain under the new hotspot. + // + // Alas, on rare occasions this heuristic can fail, and if you did nothing else you could even get stuck + // with the wrong hotspot from then on. To address that possibility, we force the hotspot to (1, 1) + // whenever the cursor being drawn is the standard arrow. Thus, while it is very unlikely that you will + // ever have the wrong hotspot, if you do, it is easy to recover. + + if (csSave->cursorHotFlag) { + csSave->cursorHotFlag = false; + D(bug("old hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY)); + + static uint8 arrow[] = { + 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0x78, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00, + 0x7F, 0x80, 0x7C, 0x00, 0x6C, 0x00, 0x46, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, + }; + if (memcmp(MacCursor + 4, arrow, 32) == 0) { + csSave->cursorHotX = 1; + csSave->cursorHotY = 1; + } else if (csSave->cursorX != oldX || csSave->cursorY != oldY) { + int32 hotX = csSave->cursorHotX + (oldX - csSave->cursorX); + int32 hotY = csSave->cursorHotY + (oldY - csSave->cursorY); + + if (0 <= hotX && hotX <= 15 && 0 <= hotY && hotY <= 15) { + csSave->cursorHotX = hotX; + csSave->cursorHotY = hotY; + } + } + if (MacCursor[2] != csSave->cursorHotX || MacCursor[3] != csSave->cursorHotY) { + MacCursor[2] = csSave->cursorHotX; + MacCursor[3] = csSave->cursorHotY; + changed = true; + } + D(bug("new hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY)); + } + + if (changed && video_can_change_cursor()) + video_set_cursor(); + return noErr; + } case 43: { // Driver Gestalt uint32 sel = ReadMacInt32(pb + csParam); @@ -859,11 +945,15 @@ case cscSupportsHardwareCursor: D(bug("SupportsHardwareCursor\n")); - WriteMacInt32(param, 1); + WriteMacInt32(param, csSave->cursorHardware); return noErr; case cscGetHardwareCursorDrawState: D(bug("GetHardwareCursorDrawState\n")); + + if (!csSave->cursorHardware) + return statusErr; + WriteMacInt32(param + csCursorX, csSave->cursorX); WriteMacInt32(param + csCursorY, csSave->cursorY); WriteMacInt32(param + csCursorVisible, csSave->cursorVisible);