From 58f4fa84259348029f50a97d84bd3b4492567645 Mon Sep 17 00:00:00 2001 From: Alexei Svitkine Date: Mon, 25 Jun 2012 12:56:58 -0400 Subject: [PATCH 01/12] Lock opened disk image files with O_EXLOCK (same as flock()) on Mac OS X to prevent concurrent access from the Finder. --- BasiliskII/src/Unix/sys_unix.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/BasiliskII/src/Unix/sys_unix.cpp b/BasiliskII/src/Unix/sys_unix.cpp index dc9892e3..b3801149 100644 --- a/BasiliskII/src/Unix/sys_unix.cpp +++ b/BasiliskII/src/Unix/sys_unix.cpp @@ -616,10 +616,26 @@ void *Sys_open(const char *name, bool read_only) } #endif + int open_flags = (read_only ? O_RDONLY : O_RDWR); #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACOSX__) - int fd = open(name, (read_only ? O_RDONLY : O_RDWR) | (is_cdrom ? O_NONBLOCK : 0)); -#else - int fd = open(name, read_only ? O_RDONLY : O_RDWR); + open_flags |= (is_cdrom ? O_NONBLOCK : 0); +#endif +#if defined(__MACOSX__) + open_flags |= (is_file ? O_EXLOCK | O_NONBLOCK : 0); +#endif + int fd = open(name, open_flags); +#if defined(__MACOSX__) + if (fd < 0 && (open_flags & O_EXLOCK)) { + if (errno == EOPNOTSUPP) { + // File system does not support locking. Try again without. + open_flags &= ~O_EXLOCK; + fd = open(name, open_flags); + } else if (errno == EAGAIN) { + // File is likely already locked by another process. + printf("WARNING: Cannot open %s (%s)\n", name, strerror(errno)); + return NULL; + } + } #endif if (fd < 0 && !read_only) { // Read-write failed, try read-only From 889c88d6c81c1065d2e41c76f3ea5b68db7535aa Mon Sep 17 00:00:00 2001 From: Alexei Svitkine Date: Sat, 30 Jun 2012 21:27:09 -0400 Subject: [PATCH 02/12] Fix inverted nocdrom check that was causing CDs not to mount. --- BasiliskII/src/MacOSX/sys_darwin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BasiliskII/src/MacOSX/sys_darwin.cpp b/BasiliskII/src/MacOSX/sys_darwin.cpp index dd6203d2..75fa2b52 100644 --- a/BasiliskII/src/MacOSX/sys_darwin.cpp +++ b/BasiliskII/src/MacOSX/sys_darwin.cpp @@ -66,7 +66,7 @@ extern void SysMediaRemoved(const char *path, int type); void DarwinSysInit(void) { - if (PrefsFindBool("nocdrom")) { + if (!PrefsFindBool("nocdrom")) { media_thread_active = (pthread_create(&media_thread, NULL, media_poll_func, NULL) == 0); D(bug("Media poll thread installed (%ld)\n", media_thread)); } From 3fc0e4dd98c69c39240d061513acddd7dadbc18b Mon Sep 17 00:00:00 2001 From: Alexei Svitkine Date: Sat, 30 Jun 2012 21:40:16 -0400 Subject: [PATCH 03/12] Rename clip_macosx64.cpp to clip_macosx64.mm in preparation for a patch from Charles Srstka. --- .../src/MacOSX/{clip_macosx64.cpp => clip_macosx64.mm} | 2 +- SheepShaver/Makefile | 2 +- .../src/MacOSX/SheepShaver.xcodeproj/project.pbxproj | 8 ++++---- SheepShaver/src/MacOSX/clip_macosx64.cpp | 1 - SheepShaver/src/MacOSX/clip_macosx64.mm | 1 + SheepShaver/src/Unix/configure.ac | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename BasiliskII/src/MacOSX/{clip_macosx64.cpp => clip_macosx64.mm} (95%) delete mode 120000 SheepShaver/src/MacOSX/clip_macosx64.cpp create mode 120000 SheepShaver/src/MacOSX/clip_macosx64.mm diff --git a/BasiliskII/src/MacOSX/clip_macosx64.cpp b/BasiliskII/src/MacOSX/clip_macosx64.mm similarity index 95% rename from BasiliskII/src/MacOSX/clip_macosx64.cpp rename to BasiliskII/src/MacOSX/clip_macosx64.mm index 068a6721..d8db1495 100644 --- a/BasiliskII/src/MacOSX/clip_macosx64.cpp +++ b/BasiliskII/src/MacOSX/clip_macosx64.mm @@ -1,5 +1,5 @@ /* - * clip_macosx64.cpp - Clipboard handling, MacOS X (Pasteboard Manager) implementation + * clip_macosx64.mm - Clipboard handling, MacOS X (Pasteboard Manager) implementation * * (C) 2012 Jean-Pierre Stierlin * (C) 2012 Alexei Svitkine diff --git a/SheepShaver/Makefile b/SheepShaver/Makefile index a5e8e7c8..8f44feed 100644 --- a/SheepShaver/Makefile +++ b/SheepShaver/Makefile @@ -73,7 +73,7 @@ links: Unix/Darwin/lowmem.c Unix/Darwin/pagezero.c Unix/Darwin/testlmem.sh \ dummy/audio_dummy.cpp dummy/clip_dummy.cpp dummy/serial_dummy.cpp \ dummy/prefs_editor_dummy.cpp dummy/scsi_dummy.cpp SDL slirp \ - MacOSX/sys_darwin.cpp MacOSX/clip_macosx.cpp MacOSX/clip_macosx64.cpp \ + MacOSX/sys_darwin.cpp MacOSX/clip_macosx.cpp MacOSX/clip_macosx64.mm \ MacOSX/macos_util_macosx.h Unix/cpr.sh \ MacOSX/extfs_macosx.cpp Windows/clip_windows.cpp \ MacOSX/MacOSX_sound_if.cpp MacOSX/MacOSX_sound_if.h \ diff --git a/SheepShaver/src/MacOSX/SheepShaver.xcodeproj/project.pbxproj b/SheepShaver/src/MacOSX/SheepShaver.xcodeproj/project.pbxproj index 9038fb72..9650252d 100644 --- a/SheepShaver/src/MacOSX/SheepShaver.xcodeproj/project.pbxproj +++ b/SheepShaver/src/MacOSX/SheepShaver.xcodeproj/project.pbxproj @@ -118,10 +118,10 @@ 0873A76A14ABD151004F12B7 /* config-macosx-x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 0873A76614ABD151004F12B7 /* config-macosx-x86_64.h */; }; 0873A76B14ABD151004F12B7 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 0873A76714ABD151004F12B7 /* config.h */; }; 0873A80214AC515D004F12B7 /* utils_macosx.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0873A80114AC515D004F12B7 /* utils_macosx.mm */; }; - 0885A52F1593E47F005C4F7B /* clip_macosx64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0851E9561593E22B00EE3FAD /* clip_macosx64.cpp */; }; 08C99DA11593E79F00898E41 /* clip_macosx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0856CE2C14A99EF0000B1711 /* clip_macosx.cpp */; }; 08CD42DC14B7B85B009CA2A2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08CD42DB14B7B85B009CA2A2 /* Cocoa.framework */; }; 08CD42E814B7B8AA009CA2A2 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08CD42E714B7B8AA009CA2A2 /* Carbon.framework */; }; + 08D93A16159FE174003B04EC /* clip_macosx64.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08D93A15159FE174003B04EC /* clip_macosx64.mm */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -214,7 +214,6 @@ 0846E52314B129DA00574779 /* ppc_asm.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = ppc_asm.S; sourceTree = ""; }; 0846E52814B129EE00574779 /* libppc_asm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libppc_asm.a; sourceTree = BUILT_PRODUCTS_DIR; }; 0846E55214B12B0D00574779 /* paranoia.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = paranoia.cpp; sourceTree = ""; }; - 0851E9561593E22B00EE3FAD /* clip_macosx64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = clip_macosx64.cpp; sourceTree = ""; }; 0856CCC114A99E1C000B1711 /* SheepShaver.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SheepShaver.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0856CD4B14A99EEF000B1711 /* adb.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = adb.cpp; path = ../adb.cpp; sourceTree = SOURCE_ROOT; }; 0856CD4C14A99EEF000B1711 /* audio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = audio.cpp; path = ../audio.cpp; sourceTree = SOURCE_ROOT; }; @@ -432,6 +431,7 @@ 0885A5341593E47F005C4F7B /* libclip64.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libclip64.a; sourceTree = BUILT_PRODUCTS_DIR; }; 08CD42DB14B7B85B009CA2A2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 08CD42E714B7B8AA009CA2A2 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = ""; }; + 08D93A15159FE174003B04EC /* clip_macosx64.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = clip_macosx64.mm; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -801,7 +801,7 @@ 0873A76514ABD151004F12B7 /* config */, 0856D2D614A9A704000B1711 /* Launcher */, 0856CE2C14A99EF0000B1711 /* clip_macosx.cpp */, - 0851E9561593E22B00EE3FAD /* clip_macosx64.cpp */, + 08D93A15159FE174003B04EC /* clip_macosx64.mm */, 0856CE2D14A99EF0000B1711 /* extfs_macosx.cpp */, 0856CE6D14A99EF0000B1711 /* macos_util_macosx.h */, 0856CE7014A99EF0000B1711 /* prefs_macosx.mm */, @@ -1461,7 +1461,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0885A52F1593E47F005C4F7B /* clip_macosx64.cpp in Sources */, + 08D93A16159FE174003B04EC /* clip_macosx64.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SheepShaver/src/MacOSX/clip_macosx64.cpp b/SheepShaver/src/MacOSX/clip_macosx64.cpp deleted file mode 120000 index 806397aa..00000000 --- a/SheepShaver/src/MacOSX/clip_macosx64.cpp +++ /dev/null @@ -1 +0,0 @@ -../../../BasiliskII/src/MacOSX/clip_macosx64.cpp \ No newline at end of file diff --git a/SheepShaver/src/MacOSX/clip_macosx64.mm b/SheepShaver/src/MacOSX/clip_macosx64.mm new file mode 120000 index 00000000..18640812 --- /dev/null +++ b/SheepShaver/src/MacOSX/clip_macosx64.mm @@ -0,0 +1 @@ +../../../BasiliskII/src/MacOSX/clip_macosx64.mm \ No newline at end of file diff --git a/SheepShaver/src/Unix/configure.ac b/SheepShaver/src/Unix/configure.ac index 4b20ee49..58d91c7c 100644 --- a/SheepShaver/src/Unix/configure.ac +++ b/SheepShaver/src/Unix/configure.ac @@ -716,7 +716,7 @@ if [[ "x$WANT_SDL_VIDEO" = "xyes" ]]; then [AC_MSG_RESULT(yes); LP64_DEFINED=yes], [AC_MSG_RESULT(no)]) if [[ "x$LP64_DEFINED" = "xyes" ]]; then - EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.cpp" + EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.mm" else EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx.cpp" fi From ed28705ee3c2ff1c382b62d638b20b7fd96e85cd Mon Sep 17 00:00:00 2001 From: CharlesJS Date: Fri, 29 Jun 2012 17:53:13 -0500 Subject: [PATCH 04/12] Patch for copying and pasting styled text in Basilisk II / SheepShaver Added code to parse the Classic Mac OS 'styl' resources, allowing formatted text to be copied and pasted out of SheepShaver, not just plain text. In order to do this, I made some changes to the emul_op mechanism, patching ZeroScrap() in addition to the scrap methods that were already being patched. The reason for this is that since we need to read data from multiple items that are on the clipboard at once, we cannot simply assume a zero at the beginning of each PutScrap() operation. This patch uses RTF to store styled text on the host side; unfortunately, since the APIs to convert to and from RTF data are in Cocoa but not in CoreFoundation, I had to write the new portions in Objective-C rather than C, and changed the extension from .cpp to .mm accordingly. In the future, if we are confident that this file will only be used on Mac OS X 10.6 and up, we can rewrite the Pasteboard Manager code to use NSPasteboardReading/Writing instead. This would allow us to read and write NSAttributedString objects directly to and from the pasteboard, which would make sure we were always using the OS's preferred rich text format internally instead of hard-coding it specifically to RTF as in the current implementation. I believe that this patch should also fix the problem Ronald reported with copying accented characters. Since I am new to 68k assembly and the emul_op mechanism, I would appreciate if someone could double-check all my changes to make sure that I have done everything correctly. Thanks, Charles --- BasiliskII/src/AmigaOS/clip_amiga.cpp | 8 + BasiliskII/src/BeOS/clip_beos.cpp | 8 + BasiliskII/src/MacOSX/clip_macosx64.mm | 703 +++++++++++++++++++++--- BasiliskII/src/Unix/clip_unix.cpp | 8 + BasiliskII/src/Windows/clip_windows.cpp | 8 + BasiliskII/src/include/clip.h | 1 + SheepShaver/src/BeOS/clip_beos.cpp | 8 + SheepShaver/src/emul_op.cpp | 4 + SheepShaver/src/include/emul_op.h | 3 +- SheepShaver/src/rom_patches.cpp | 19 +- 10 files changed, 676 insertions(+), 94 deletions(-) diff --git a/BasiliskII/src/AmigaOS/clip_amiga.cpp b/BasiliskII/src/AmigaOS/clip_amiga.cpp index 24d1b2d8..10336bbd 100644 --- a/BasiliskII/src/AmigaOS/clip_amiga.cpp +++ b/BasiliskII/src/AmigaOS/clip_amiga.cpp @@ -97,6 +97,14 @@ void ClipExit(void) FreeIFF(iffw); } +/* + * Mac application zeroes clipboard + */ + +void ZeroScrap() +{ + +} /* * Mac application reads clipboard diff --git a/BasiliskII/src/BeOS/clip_beos.cpp b/BasiliskII/src/BeOS/clip_beos.cpp index 3044c34e..10159ec6 100644 --- a/BasiliskII/src/BeOS/clip_beos.cpp +++ b/BasiliskII/src/BeOS/clip_beos.cpp @@ -52,6 +52,14 @@ void ClipExit(void) { } +/* + * Mac application zeroes clipboard + */ + +void ZeroScrap() +{ + +} /* * Mac application reads clipboard diff --git a/BasiliskII/src/MacOSX/clip_macosx64.mm b/BasiliskII/src/MacOSX/clip_macosx64.mm index d8db1495..1d906a75 100644 --- a/BasiliskII/src/MacOSX/clip_macosx64.mm +++ b/BasiliskII/src/MacOSX/clip_macosx64.mm @@ -3,6 +3,7 @@ * * (C) 2012 Jean-Pierre Stierlin * (C) 2012 Alexei Svitkine + * (C) 2012 Charles Srstka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +22,7 @@ #include "sysdeps.h" #define _UINT64 +#import #include #include "clip.h" @@ -37,23 +39,41 @@ #define TYPE_PICT FOURCC('P','I','C','T') #define TYPE_TEXT FOURCC('T','E','X','T') +#define TYPE_STYL FOURCC('s','t','y','l') static PasteboardRef g_pbref; // Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the MacOS X side static bool we_put_this_data = false; +static bool should_clear = false; + +static CFStringRef const UTF16_TEXT_FLAVOR_NAME = CFSTR("public.utf16-plain-text"); +static CFStringRef const TEXT_FLAVOR_NAME = CFSTR("com.apple.traditional-mac-plain-text"); +static CFStringRef const STYL_FLAVOR_NAME = CFSTR("net.cebix.basilisk.styl-data"); + +enum { + FONT_FACE_PLAIN = 0, + FONT_FACE_BOLD = 1, + FONT_FACE_ITALIC = 2, + FONT_FACE_UNDERLINE = 4, + FONT_FACE_OUTLINE = 8, + FONT_FACE_SHADOW = 16, + FONT_FACE_CONDENSED = 32, + FONT_FACE_EXTENDED = 64 +}; + static CFStringRef GetUTIFromFlavor(uint32 type) { switch (type) { case TYPE_PICT: return kUTTypePICT; - case TYPE_TEXT: return CFSTR("com.apple.traditional-mac-plain-text"); - //case TYPE_TEXT: return CFSTR("public.utf16-plain-text"); - //case FOURCC('s','t','y','l'): return CFSTR("????"); + case TYPE_TEXT: return TEXT_FLAVOR_NAME; + //case TYPE_TEXT: return UTF16_TEXT_FLAVOR_NAME; + case TYPE_STYL: return STYL_FLAVOR_NAME; case FOURCC('m','o','o','v'): return kUTTypeQuickTimeMovie; case FOURCC('s','n','d',' '): return kUTTypeAudio; - //case FOURCC('u','t','x','t'): return CFSTR("public.utf16-plain-text"); - case FOURCC('u','t','1','6'): return CFSTR("public.utf16-plain-text"); + //case FOURCC('u','t','x','t'): return UTF16_TEXT_FLAVOR_NAME; + case FOURCC('u','t','1','6'): return UTF16_TEXT_FLAVOR_NAME; //case FOURCC('u','s','t','l'): return CFSTR("????"); case FOURCC('i','c','n','s'): return kUTTypeAppleICNS; default: return NULL; @@ -97,7 +117,7 @@ static int GetMacScriptManagerVariable(uint16 id) * Convert utf-16 from/to system script encoding on Mac */ -CFDataRef ConvertMacTextEncoding(CFDataRef pbData, int from_host) +static CFDataRef ConvertMacTextEncoding(CFDataRef pbData, int from_host) { static TextEncoding g_textEncodingHint = kTextEncodingUnknown; static UnicodeMapping uMapping; @@ -124,21 +144,21 @@ CFDataRef ConvertMacTextEncoding(CFDataRef pbData, int from_host) LogicalAddress outBytesPtr = malloc(byteCount * 2); if (!outBytesPtr) return pbData; - + ByteCount outBytesConverted; OSStatus err; if (from_host) { err = ConvertFromUnicodeToText(utInfo, byteCount, (UniChar *)CFDataGetBytePtr(pbData), - kUnicodeLooseMappingsMask, - 0, NULL, 0, NULL, - outBytesLength, - &outBytesConverted, &outBytesLength, outBytesPtr); + kUnicodeLooseMappingsMask, + 0, NULL, 0, NULL, + outBytesLength, + &outBytesConverted, &outBytesLength, outBytesPtr); } else { err = ConvertFromTextToUnicode(tuInfo, byteCount, CFDataGetBytePtr(pbData), - kUnicodeLooseMappingsMask, - 0, NULL, 0, NULL, - outBytesLength, - &outBytesConverted, &outBytesLength, (UniChar *)outBytesPtr); + kUnicodeLooseMappingsMask, + 0, NULL, 0, NULL, + outBytesLength, + &outBytesConverted, &outBytesLength, (UniChar *)outBytesPtr); } if (err == noErr && outBytesConverted == byteCount) { @@ -153,6 +173,393 @@ CFDataRef ConvertMacTextEncoding(CFDataRef pbData, int from_host) return pbData; } +/* + * Convert Mac font ID to font name + */ + +static NSString *FontNameFromFontID(int16_t fontID) +{ + M68kRegisters r; + r.d[0] = 256; // Str255: 255 characters + length byte + Execute68kTrap(0xa71e, &r); // NewPtrSysClear() + uint32_t name_area = r.a[0]; + + if (!name_area) + return nil; + + uint8_t proc[] = { + 0x3f, 0x3c, 0, 0, // move.w #fontID,-(sp) + 0x2f, 0x0a, // move.l A2,-(sp) + 0xa8, 0xff, // GetFontName() + M68K_RTS >> 8, M68K_RTS & 0xff + }; + + r.d[0] = sizeof(proc); + Execute68kTrap(0xa71e, &r); // NewPtrSysClear() + uint32_t proc_area = r.a[0]; + + if (proc_area) { + Host2Mac_memcpy(proc_area, proc, sizeof(proc)); + WriteMacInt16(proc_area + 2, fontID); + r.a[2] = name_area; + Execute68k(proc_area, &r); + + r.a[0] = proc_area; + Execute68kTrap(0xa01f, &r); // DisposePtr + } + + uint8_t * const namePtr = Mac2HostAddr(name_area); + + CFStringRef name = CFStringCreateWithPascalString(kCFAllocatorDefault, namePtr, kCFStringEncodingMacRoman); + + r.a[0] = name_area; + Execute68kTrap(0xa01f, &r); // DisposePtr + + return [(NSString *)name autorelease]; +} + +/* + * Convert font name to Mac font ID + */ + +static int16_t FontIDFromFontName(NSString *fontName) +{ + M68kRegisters r; + r.d[0] = 256; // Str255: 255 characters + length byte + Execute68kTrap(0xa71e, &r); // NewPtrSysClear() + uint32_t name_area = r.a[0]; + + if (!name_area) + return 0; + + uint8_t * const namePtr = Mac2HostAddr(name_area); + + CFStringGetPascalString((CFStringRef)fontName, namePtr, 256, kCFStringEncodingMacRoman); + + uint8_t proc[] = { + 0x2f, 0x0a, // move.l A2,-(sp) + 0x2f, 0x0b, // move.l A3,-(sp) + 0xa9, 0x00, // GetFNum() + M68K_RTS >> 8, M68K_RTS & 0xff, + 0, 0 + }; + + r.d[0] = sizeof(proc); + Execute68kTrap(0xa71e, &r); // NewPtrSysClear() + uint32_t proc_area = r.a[0]; + int16_t fontID = 0; + + if (proc_area) { + Host2Mac_memcpy(proc_area, proc, sizeof(proc)); + r.a[2] = name_area; + r.a[3] = proc_area + 8; + + Execute68k(proc_area, &r); + + fontID = ReadMacInt16(proc_area + 8); + + r.a[0] = proc_area; + Execute68kTrap(0xa01f, &r); // DisposePtr + } + + r.a[0] = name_area; + Execute68kTrap(0xa01f, &r); // DisposePtr + + return fontID; +} + +/* + * Convert Mac styl to attributed string + */ + +static NSAttributedString *ConvertToAttributedString(NSString *string, NSData *stylData) +{ + NSMutableAttributedString *aStr = [[[NSMutableAttributedString alloc] initWithString:string] autorelease]; + + if (aStr == nil) + return nil; + + const uint8_t *bytes = (const uint8_t *)[stylData bytes]; + NSUInteger length = [stylData length]; + + if (length < 2) + return nil; + + uint16_t elements = CFSwapInt16BigToHost(*(uint16_t *)bytes); + const NSUInteger elementSize = 20; + + if (length < elements * elementSize) + return nil; + + CFIndex pointer = 2; + + for (NSUInteger i = 0; i < elements; i++) { + int32_t startChar = CFSwapInt32BigToHost(*(int32_t *)(bytes + pointer)); pointer += 4; + int16_t height = CFSwapInt16BigToHost(*(int16_t *)&bytes[pointer]); pointer += 2; + int16_t ascent = CFSwapInt16BigToHost(*(int16_t *)&bytes[pointer]); pointer += 2; + int16_t fontID = CFSwapInt16BigToHost(*(int16_t *)&bytes[pointer]); pointer += 2; + uint8_t face = bytes[pointer]; pointer += 2; + int16_t size = CFSwapInt16BigToHost(*(int16_t *)&bytes[pointer]); pointer += 2; + uint16_t red = CFSwapInt16BigToHost(*(int16_t *)&bytes[pointer]); pointer += 2; + uint16_t green = CFSwapInt16BigToHost(*(int16_t *)&bytes[pointer]); pointer += 2; + uint16_t blue = CFSwapInt16BigToHost(*(int16_t *)&bytes[pointer]); pointer += 2; + + int32_t nextChar; + + if (i + 1 == elements) + nextChar = [aStr length]; + else + nextChar = CFSwapInt32BigToHost(*(int32_t *)(bytes + pointer)); + + NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init]; + NSColor *color = [NSColor colorWithDeviceRed:(CGFloat)red / 65535.0 green:(CGFloat)green / 65535.0 blue:(CGFloat)blue / 65535.0 alpha:1.0]; + NSFont *font; + + if (fontID == 0) { // System font + CGFloat fontSize = (size == 0) ? [NSFont systemFontSize] : (CGFloat)size; + font = [NSFont systemFontOfSize:fontSize]; + } else if (fontID == 1) { // Application font + font = [NSFont userFontOfSize:(CGFloat)size]; + } else { + NSString *fontName = FontNameFromFontID(fontID); + font = [NSFont fontWithName:fontName size:(CGFloat)size]; + } + + if (font == nil) + font = [NSFont userFontOfSize:(CGFloat)size]; + + NSFontManager *fm = [NSFontManager sharedFontManager]; + + if (face & FONT_FACE_BOLD) + font = [fm convertFont:font toHaveTrait:NSBoldFontMask]; + + if (face & FONT_FACE_ITALIC) + font = [fm convertFont:font toHaveTrait:NSItalicFontMask]; + + if (face & FONT_FACE_CONDENSED) + font = [fm convertFont:font toHaveTrait:NSCondensedFontMask]; + + if (face & FONT_FACE_EXTENDED) + font = [fm convertFont:font toHaveTrait:NSExpandedFontMask]; + + [attrs setObject:font forKey:NSFontAttributeName]; + + if (face & FONT_FACE_UNDERLINE) + [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName]; + + if (face & FONT_FACE_OUTLINE) { + [attrs setObject:color forKey:NSStrokeColorAttributeName]; + [attrs setObject:[NSNumber numberWithInteger:3] forKey:NSStrokeWidthAttributeName]; + } + + if (face & FONT_FACE_SHADOW) { + NSShadow *shadow = [[NSShadow alloc] init]; + NSColor *shadowColor = [NSColor colorWithDeviceRed:(CGFloat)red / 65535.0 green:(CGFloat)green / 65535.0 blue:(CGFloat)blue / 65535.0 alpha:0.5]; + + [shadow setShadowColor:shadowColor]; + [shadow setShadowOffset:NSMakeSize(2, -2.0)]; + + [attrs setObject:shadow forKey:NSShadowAttributeName]; + + [shadow release]; + } + + [attrs setObject:color forKey:NSForegroundColorAttributeName]; + + [aStr setAttributes:attrs range:NSMakeRange(startChar, nextChar - startChar)]; + + [attrs release]; + } + + return aStr; +} + +/* + * Convert attributed string to TEXT/styl + */ + +static NSData *ConvertToMacTEXTAndStyl(NSAttributedString *aStr, NSData **outStylData) { + // Limitations imposed by the Mac TextEdit system. + // Something to test would be whether using UTF16 causes TextEdit to choke at 16K characters + // instead of 32K characters, depending on whether this is a byte limit or a true character limit. + // If the former, UTF8 might be a better choice for encoding here. + const NSUInteger charLimit = 32 * 1024; + const NSUInteger elementLimit = 1601; + + if([aStr length] > charLimit) { + aStr = [aStr attributedSubstringFromRange:NSMakeRange(0, charLimit)]; + } + + // See comment in CreateRTFDataFromMacTEXTAndStyl regarding encodings; I hope I've interpreted + // the existing code correctly in this regard +#if __LITTLE_ENDIAN__ + NSStringEncoding encoding = NSUTF16LittleEndianStringEncoding; +#else + NSStringEncoding encoding = NSUTF16BigEndianStringEncoding; +#endif + + NSData *textData = [[aStr string] dataUsingEncoding:encoding]; + NSMutableData *stylData = [NSMutableData dataWithLength:2]; // number of styles to be filled in at the end + + NSUInteger length = [aStr length]; + NSUInteger elements = 0; + + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + NSLayoutManager *layoutManager = [[[NSLayoutManager alloc] init] autorelease]; + + for (NSUInteger index = 0; index < length && elements < elementLimit;) { + NSRange attrRange; + NSDictionary *attrs = [aStr attributesAtIndex:index effectiveRange:&attrRange]; + + NSFont *font = [attrs objectForKey:NSFontAttributeName]; + NSColor *color = [[attrs objectForKey:NSForegroundColorAttributeName] colorUsingColorSpaceName:NSDeviceRGBColorSpace device:nil]; + NSFontTraitMask traits = [fontManager traitsOfFont:font]; + NSNumber *underlineStyle = [attrs objectForKey:NSUnderlineStyleAttributeName]; + NSNumber *strokeWidth = [attrs objectForKey:NSStrokeWidthAttributeName]; + NSShadow *shadow = [attrs objectForKey:NSShadowAttributeName]; + + int16_t hostFontID = FontIDFromFontName([font familyName]); + + if (hostFontID == 0) { + hostFontID = [font isFixedPitch] ? 4 /* Monaco */ : 1 /* Application font */; + } + + int32_t startChar = CFSwapInt32HostToBig((int32_t)index); + int16_t height = CFSwapInt16HostToBig((int16_t)rint([layoutManager defaultLineHeightForFont:font])); + int16_t ascent = CFSwapInt16HostToBig((int16_t)rint([font ascender])); + int16_t fontID = CFSwapInt16HostToBig(hostFontID); + uint8_t face = 0; + int16_t size = CFSwapInt16HostToBig((int16_t)rint([font pointSize])); + uint16_t red = CFSwapInt16HostToBig((int16_t)rint([color redComponent] * 65535.0)); + uint16_t green = CFSwapInt16HostToBig((int16_t)rint([color greenComponent] * 65535.0)); + uint16_t blue = CFSwapInt16HostToBig((int16_t)rint([color blueComponent] * 65535.0)); + + if (traits & NSBoldFontMask) { + face |= FONT_FACE_BOLD; + } + + if (traits & NSItalicFontMask) { + face |= FONT_FACE_ITALIC; + } + + if (traits & NSCondensedFontMask) { + face |= FONT_FACE_CONDENSED; + } + + if (traits & NSExpandedFontMask) { + face |= FONT_FACE_EXTENDED; + } + + if (underlineStyle && [underlineStyle integerValue] != NSUnderlineStyleNone) { + face |= FONT_FACE_UNDERLINE; + } + + if (strokeWidth && [strokeWidth doubleValue] > 0.0) { + face |= FONT_FACE_OUTLINE; + } + + if (shadow) { + face |= FONT_FACE_SHADOW; + } + + [stylData appendBytes:&startChar length:4]; + [stylData appendBytes:&height length:2]; + [stylData appendBytes:&ascent length:2]; + [stylData appendBytes:&fontID length:2]; + [stylData appendBytes:&face length:1]; + [stylData increaseLengthBy:1]; + [stylData appendBytes:&size length:2]; + [stylData appendBytes:&red length:2]; + [stylData appendBytes:&green length:2]; + [stylData appendBytes:&blue length:2]; + + index += attrRange.length; + elements++; + } + + uint16_t bigEndianElements = CFSwapInt16HostToBig((uint16_t)elements); + + [stylData replaceBytesInRange:NSMakeRange(0, 2) withBytes:&bigEndianElements length:2]; + + if (outStylData) + *outStylData = stylData; + + textData = (NSData *)ConvertMacTextEncoding((CFDataRef)[textData retain], YES); + + return [textData autorelease]; +} + +/* + * Convert Mac TEXT/styl to RTF + */ + +static CFDataRef CreateRTFDataFromMacTEXTAndStyl(CFDataRef textData, CFDataRef stylData) +{ + // Unfortunately, CF does not seem to have any RTF conversion routines, so do this in Cocoa instead. + // If we are willing to require OS X 10.6 minimum, we should use the NSPasteboardWriting methods + // instead of putting the RTF data up ourselves. + + NSData *rtfData = nil; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + // I think this is what's going on? ConvertMacTextEncoding() converts to Unicode in host endian? + // Maybe UTF8 would be a less ambiguous form to store the pasteboard data in? + +#if __LITTLE_ENDIAN__ + NSStringEncoding encoding = NSUTF16LittleEndianStringEncoding; +#else + NSStringEncoding encoding = NSUTF16BigEndianStringEncoding; +#endif + + NSMutableString *string = [[[NSMutableString alloc] initWithData:(NSData *)textData encoding:encoding] autorelease]; + + // fix line endings + [string replaceOccurrencesOfString:@"\r" withString:@"\n" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; + + if (string != nil) { + NSAttributedString *aStr = ConvertToAttributedString(string, (NSData *)stylData); + + rtfData = [[aStr RTFFromRange:NSMakeRange(0, [aStr length]) documentAttributes:nil] retain]; + } + + [pool drain]; + + return (CFDataRef)rtfData; +} + +/* + * Convert RTF to Mac TEXT/styl + */ + +static CFDataRef CreateMacTEXTAndStylFromRTFData(CFDataRef rtfData, CFDataRef *outStylData) +{ + // No easy way to do this at the CF layer, so use Cocoa. + // Reading RTF should be backward compatible to the early releases of OS X; + // if we are willing to require OS X 10.6 or better, we should use NSPasteboardReading + // to read an NSAttributedString off of the pasteboard, which will give us the ability + // to potentially read more rich-text formats than RTF. + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSMutableAttributedString *aStr = [[[NSMutableAttributedString alloc] initWithRTF:(NSData *)rtfData documentAttributes:nil] autorelease]; + + // fix line endings + [[aStr mutableString] replaceOccurrencesOfString:@"\n" withString:@"\r" options:NSLiteralSearch range:NSMakeRange(0, [[aStr mutableString] length])]; + + NSData *stylData = nil; + NSData *textData = ConvertToMacTEXTAndStyl(aStr, &stylData); + + [textData retain]; + + if (outStylData) + *outStylData = (CFDataRef)[stylData retain]; + + [pool drain]; + + return (CFDataRef)textData; +} + /* * Initialization */ @@ -179,6 +586,110 @@ void ClipExit(void) } } +/* + * Copy data from the host pasteboard + */ + +static CFDataRef CopyPasteboardDataWithFlavor(CFStringRef flavor) +{ + ItemCount itemCount; + + if (PasteboardGetItemCount(g_pbref, &itemCount)) + return NULL; + + for (UInt32 itemIndex = 1; itemIndex <= itemCount; itemIndex++) { + PasteboardItemID itemID; + CFDataRef pbData; + + if (PasteboardGetItemIdentifier(g_pbref, itemIndex, &itemID)) + break; + + if (!PasteboardCopyItemFlavorData(g_pbref, itemID, flavor, &pbData)) { + return pbData; + } + } + + return NULL; +} + +/* + * Zero Mac clipboard + */ + +static void ZeroMacClipboard() +{ + D(bug(stderr, "Zeroing Mac clipboard\n")); + M68kRegisters r; + static uint8 proc[] = { + 0x59, 0x8f, // subq.l #4,sp + 0xa9, 0xfc, // ZeroScrap() + 0x58, 0x8f, // addq.l #4,sp + M68K_RTS >> 8, M68K_RTS & 0xff + }; + r.d[0] = sizeof(proc); + Execute68kTrap(0xa71e, &r); // NewPtrSysClear() + uint32 proc_area = r.a[0]; + + if (proc_area) { + Host2Mac_memcpy(proc_area, proc, sizeof(proc)); + Execute68k(proc_area, &r); + + r.a[0] = proc_area; + Execute68kTrap(0xa01f, &r); // DisposePtr + } +} + +/* + * Write data to Mac clipboard + */ + +static void WriteDataToMacClipboard(CFDataRef pbData, uint32 type) +{ + D(bug(stderr, "Writing data %s to Mac clipboard with type '%c%c%c%c'\n", [[(NSData *)pbData description] UTF8String], + (type >> 24) & 0xff, (type >> 16) & 0xff, (type >> 8) & 0xff, type & 0xff)); + + // Allocate space for new scrap in MacOS side + M68kRegisters r; + r.d[0] = CFDataGetLength(pbData); + Execute68kTrap(0xa71e, &r); // NewPtrSysClear() + uint32 scrap_area = r.a[0]; + + // Get the native clipboard data + if (scrap_area) { + uint8 * const data = Mac2HostAddr(scrap_area); + + memcpy(data, CFDataGetBytePtr(pbData), CFDataGetLength(pbData)); + + // Add new data to clipboard + static uint8 proc[] = { + 0x59, 0x8f, // subq.l #4,sp + 0x2f, 0x3c, 0, 0, 0, 0, // move.l #length,-(sp) + 0x2f, 0x3c, 0, 0, 0, 0, // move.l #type,-(sp) + 0x2f, 0x3c, 0, 0, 0, 0, // move.l #outbuf,-(sp) + 0xa9, 0xfe, // PutScrap() + 0x58, 0x8f, // addq.l #4,sp + M68K_RTS >> 8, M68K_RTS & 0xff + }; + r.d[0] = sizeof(proc); + Execute68kTrap(0xa71e, &r); // NewPtrSysClear() + uint32 proc_area = r.a[0]; + + if (proc_area) { + Host2Mac_memcpy(proc_area, proc, sizeof(proc)); + WriteMacInt32(proc_area + 4, CFDataGetLength(pbData)); + WriteMacInt32(proc_area + 10, type); + WriteMacInt32(proc_area + 16, scrap_area); + we_put_this_data = true; + Execute68k(proc_area, &r); + + r.a[0] = proc_area; + Execute68kTrap(0xa01f, &r); // DisposePtr + } + + r.a[0] = scrap_area; + Execute68kTrap(0xa01f, &r); // DisposePtr + } +} /* * Mac application reads clipboard @@ -186,86 +697,70 @@ void ClipExit(void) void GetScrap(void **handle, uint32 type, int32 offset) { - D(bug("GetScrap handle %p, type %4.4s, offset %d\n", handle, &type, offset)); - + D(bug("GetScrap handle %p, type %4.4s, offset %d\n", handle, (char *)&type, offset)); + CFStringRef typeStr; PasteboardSyncFlags syncFlags; - ItemCount itemCount; - + if (!g_pbref) return; - + syncFlags = PasteboardSynchronize(g_pbref); if (syncFlags & kPasteboardModified) return; - - if (PasteboardGetItemCount(g_pbref, &itemCount)) - return; if (!(typeStr = GetUTIFromFlavor(type))) return; - - for (UInt32 itemIndex = 1; itemIndex <= itemCount; itemIndex++) { - PasteboardItemID itemID; - CFDataRef pbData; - - if (PasteboardGetItemIdentifier(g_pbref, itemIndex, &itemID)) - break; - if (!PasteboardCopyItemFlavorData(g_pbref, itemID, typeStr, &pbData)) { - if (type == TYPE_TEXT) - pbData = ConvertMacTextEncoding(pbData, TRUE); - if (pbData) { - // Allocate space for new scrap in MacOS side - M68kRegisters r; - r.d[0] = CFDataGetLength(pbData); - Execute68kTrap(0xa71e, &r); // NewPtrSysClear() - uint32 scrap_area = r.a[0]; - - // Get the native clipboard data - if (scrap_area) { - uint8 * const data = Mac2HostAddr(scrap_area); - - memcpy(data, CFDataGetBytePtr(pbData), CFDataGetLength(pbData)); - - // Add new data to clipboard - static uint8 proc[] = { - 0x59, 0x8f, // subq.l #4,sp - 0xa9, 0xfc, // ZeroScrap() - 0x2f, 0x3c, 0, 0, 0, 0, // move.l #length,-(sp) - 0x2f, 0x3c, 0, 0, 0, 0, // move.l #type,-(sp) - 0x2f, 0x3c, 0, 0, 0, 0, // move.l #outbuf,-(sp) - 0xa9, 0xfe, // PutScrap() - 0x58, 0x8f, // addq.l #4,sp - M68K_RTS >> 8, M68K_RTS & 0xff - }; - r.d[0] = sizeof(proc); - Execute68kTrap(0xa71e, &r); // NewPtrSysClear() - uint32 proc_area = r.a[0]; + if (type == TYPE_TEXT || type == TYPE_STYL) { + CFDataRef rtfData = CopyPasteboardDataWithFlavor(kUTTypeRTF); + + if (rtfData != NULL) { + CFDataRef stylData = NULL; + CFDataRef textData = CreateMacTEXTAndStylFromRTFData(rtfData, &stylData); - if (proc_area) { - Host2Mac_memcpy(proc_area, proc, sizeof(proc)); - WriteMacInt32(proc_area + 6, CFDataGetLength(pbData)); - WriteMacInt32(proc_area + 12, type); - WriteMacInt32(proc_area + 18, scrap_area); - we_put_this_data = true; - Execute68k(proc_area, &r); + ZeroMacClipboard(); - r.a[0] = proc_area; - Execute68kTrap(0xa01f, &r); // DisposePtr - } + if(stylData) + WriteDataToMacClipboard(stylData, TYPE_STYL); - r.a[0] = scrap_area; - Execute68kTrap(0xa01f, &r); // DisposePtr - } - } - - CFRelease(pbData); - break; + WriteDataToMacClipboard(textData, TYPE_TEXT); + + CFRelease(textData); + CFRelease(stylData); + CFRelease(rtfData); + + return; } } + + CFDataRef pbData = CopyPasteboardDataWithFlavor(typeStr); + + if (pbData) { + if (type == TYPE_TEXT) + pbData = ConvertMacTextEncoding(pbData, TRUE); + + ZeroMacClipboard(); + WriteDataToMacClipboard(pbData, type); + + CFRelease(pbData); + } } +/* + * ZeroScrap() is called before a Mac application writes to the clipboard; clears out the previous contents + */ + +void ZeroScrap() +{ + D(bug("ZeroScrap\n")); + + we_put_this_data = false; + + // Defer clearing the host pasteboard until the Mac tries to put something on it. + // This prevents us from clearing the pasteboard when ZeroScrap() is called during startup. + should_clear = true; +} /* * Mac application wrote to clipboard @@ -273,41 +768,69 @@ void GetScrap(void **handle, uint32 type, int32 offset) void PutScrap(uint32 type, void *scrap, int32 length) { - static bool clear = true; - D(bug("PutScrap type %4.4s, data %08lx, length %ld\n", &type, scrap, length)); - + D(bug("PutScrap type %4.4s, data %p, length %ld\n", (char *)&type, scrap, (long)length)); + PasteboardSyncFlags syncFlags; CFStringRef typeStr; - + if (!g_pbref) return; - + if (!(typeStr = GetUTIFromFlavor(type))) return; - + if (we_put_this_data) { we_put_this_data = false; - clear = true; return; } if (length <= 0) return; - - if (clear && PasteboardClear(g_pbref)) - return; + + if (should_clear) { + PasteboardClear(g_pbref); + should_clear = false; + } + syncFlags = PasteboardSynchronize(g_pbref); if ((syncFlags & kPasteboardModified) || !(syncFlags & kPasteboardClientIsOwner)) return; - + CFDataRef pbData = CFDataCreate(kCFAllocatorDefault, (UInt8*)scrap, length); if (!pbData) return; - + + if (type == TYPE_TEXT) pbData = ConvertMacTextEncoding(pbData, FALSE); - + if (pbData) { PasteboardPutItemFlavor(g_pbref, (PasteboardItemID)1, typeStr, pbData, 0); CFRelease(pbData); } + + if (type == TYPE_TEXT || type == TYPE_STYL) { + CFDataRef textData; + CFDataRef stylData; + + if (PasteboardCopyItemFlavorData(g_pbref, (PasteboardItemID)1, TEXT_FLAVOR_NAME, &textData) != noErr) + textData = NULL; + + if (PasteboardCopyItemFlavorData(g_pbref, (PasteboardItemID)1, STYL_FLAVOR_NAME, &stylData) != noErr) + stylData = NULL; + + if (textData != NULL && stylData != NULL) { + CFDataRef rtfData = CreateRTFDataFromMacTEXTAndStyl(textData, stylData); + + if (rtfData) { + PasteboardPutItemFlavor(g_pbref, (PasteboardItemID)1, kUTTypeRTF, rtfData, 0); + CFRelease(rtfData); + } + } + + if (textData) + CFRelease(textData); + + if (stylData) + CFRelease(stylData); + } } diff --git a/BasiliskII/src/Unix/clip_unix.cpp b/BasiliskII/src/Unix/clip_unix.cpp index 186aff58..36c9b4db 100644 --- a/BasiliskII/src/Unix/clip_unix.cpp +++ b/BasiliskII/src/Unix/clip_unix.cpp @@ -374,6 +374,14 @@ static void do_putscrap(uint32 type, void *scrap, int32 length) } } +/* + * Mac application zeroes clipboard + */ + +void ZeroScrap() +{ + +} /* * Mac application reads clipboard diff --git a/BasiliskII/src/Windows/clip_windows.cpp b/BasiliskII/src/Windows/clip_windows.cpp index eab99f2f..1e6f982b 100755 --- a/BasiliskII/src/Windows/clip_windows.cpp +++ b/BasiliskII/src/Windows/clip_windows.cpp @@ -179,6 +179,14 @@ static void do_putscrap(uint32 type, void *scrap, int32 length) CloseClipboard(); } +/* + * Mac application zeroes clipboard + */ + +void ZeroScrap() +{ + +} /* * Mac application reads clipboard diff --git a/BasiliskII/src/include/clip.h b/BasiliskII/src/include/clip.h index fd45845e..3ea43595 100644 --- a/BasiliskII/src/include/clip.h +++ b/BasiliskII/src/include/clip.h @@ -24,6 +24,7 @@ extern void ClipInit(void); extern void ClipExit(void); +extern void ZeroScrap(); extern void PutScrap(uint32 type, void *scrap, int32 length); extern void GetScrap(void **handle, uint32 type, int32 offset); diff --git a/SheepShaver/src/BeOS/clip_beos.cpp b/SheepShaver/src/BeOS/clip_beos.cpp index b08bf59a..953ed804 100644 --- a/SheepShaver/src/BeOS/clip_beos.cpp +++ b/SheepShaver/src/BeOS/clip_beos.cpp @@ -240,6 +240,14 @@ void PutScrap(uint32 type, void *scrap, int32 length) } } +/* + * Mac application zeroes clipboard + */ + +void ZeroScrap() +{ + +} /* * Mac application reads clipboard diff --git a/SheepShaver/src/emul_op.cpp b/SheepShaver/src/emul_op.cpp index 6c5b416a..9e01554d 100644 --- a/SheepShaver/src/emul_op.cpp +++ b/SheepShaver/src/emul_op.cpp @@ -227,6 +227,10 @@ void EmulOp(M68kRegisters *r, uint32 pc, int selector) Microseconds(r->a[0], r->d[0]); break; + case OP_ZERO_SCRAP: // ZeroScrap() patch + ZeroScrap(); + break; + case OP_PUT_SCRAP: // PutScrap() patch PutScrap(ReadMacInt32(r->a[7] + 8), Mac2HostAddr(ReadMacInt32(r->a[7] + 4)), ReadMacInt32(r->a[7] + 12)); break; diff --git a/SheepShaver/src/include/emul_op.h b/SheepShaver/src/include/emul_op.h index 78f35e0d..9f9a323e 100644 --- a/SheepShaver/src/include/emul_op.h +++ b/SheepShaver/src/include/emul_op.h @@ -44,7 +44,7 @@ enum { // Selectors for EMUL_OP opcodes OP_DISK_OPEN, OP_DISK_PRIME, OP_DISK_CONTROL, OP_DISK_STATUS, OP_CDROM_OPEN, OP_CDROM_PRIME, OP_CDROM_CONTROL, OP_CDROM_STATUS, OP_AUDIO_DISPATCH, OP_SOUNDIN_OPEN, OP_SOUNDIN_PRIME, OP_SOUNDIN_CONTROL, OP_SOUNDIN_STATUS, OP_SOUNDIN_CLOSE, - OP_ADBOP, OP_INSTIME, OP_RMVTIME, OP_PRIMETIME, OP_MICROSECONDS, OP_PUT_SCRAP, OP_GET_SCRAP, + OP_ADBOP, OP_INSTIME, OP_RMVTIME, OP_PRIMETIME, OP_MICROSECONDS, OP_ZERO_SCRAP, OP_PUT_SCRAP, OP_GET_SCRAP, OP_DEBUG_STR, OP_INSTALL_DRIVERS, OP_NAME_REGISTRY, OP_RESET, OP_IRQ, OP_SCSI_DISPATCH, OP_SCSI_ATOMIC, OP_CHECK_SYSV, OP_NTRB_17_PATCH, OP_NTRB_17_PATCH2, OP_NTRB_17_PATCH3, OP_NTRB_17_PATCH4, OP_CHECKLOAD, @@ -87,6 +87,7 @@ const uint16 M68K_EMUL_OP_INSTIME = M68K_EMUL_BREAK + OP_INSTIME; const uint16 M68K_EMUL_OP_RMVTIME = M68K_EMUL_BREAK + OP_RMVTIME; const uint16 M68K_EMUL_OP_PRIMETIME = M68K_EMUL_BREAK + OP_PRIMETIME; const uint16 M68K_EMUL_OP_MICROSECONDS = M68K_EMUL_BREAK + OP_MICROSECONDS; +const uint16 M68K_EMUL_OP_ZERO_SCRAP = M68K_EMUL_BREAK + OP_ZERO_SCRAP; const uint16 M68K_EMUL_OP_PUT_SCRAP = M68K_EMUL_BREAK + OP_PUT_SCRAP; const uint16 M68K_EMUL_OP_GET_SCRAP = M68K_EMUL_BREAK + OP_GET_SCRAP; const uint16 M68K_EMUL_OP_DEBUG_STR = M68K_EMUL_BREAK + OP_DEBUG_STR; diff --git a/SheepShaver/src/rom_patches.cpp b/SheepShaver/src/rom_patches.cpp index dac6c0bb..9dcd826a 100644 --- a/SheepShaver/src/rom_patches.cpp +++ b/SheepShaver/src/rom_patches.cpp @@ -60,9 +60,10 @@ // Other ROM addresses const uint32 CHECK_LOAD_PATCH_SPACE = 0x2fcf00; -const uint32 PUT_SCRAP_PATCH_SPACE = 0x2fcf80; -const uint32 GET_SCRAP_PATCH_SPACE = 0x2fcfc0; -const uint32 ADDR_MAP_PATCH_SPACE = 0x2fd100; +const uint32 ZERO_SCRAP_PATCH_SPACE = 0x2fcf80; +const uint32 PUT_SCRAP_PATCH_SPACE = 0x2fcfc0; +const uint32 GET_SCRAP_PATCH_SPACE = 0x2fd100; +const uint32 ADDR_MAP_PATCH_SPACE = 0x2fd140; // Global variables int ROMType; // ROM type @@ -713,6 +714,8 @@ bool PatchROM(void) // Check that other ROM addresses point to really free regions if (!check_rom_patch_space(CHECK_LOAD_PATCH_SPACE, 0x40)) return false; + if (!check_rom_patch_space(ZERO_SCRAP_PATCH_SPACE, 0x40)) + return false; if (!check_rom_patch_space(PUT_SCRAP_PATCH_SPACE, 0x40)) return false; if (!check_rom_patch_space(GET_SCRAP_PATCH_SPACE, 0x40)) @@ -2296,6 +2299,16 @@ static bool patch_68k(void) *wp = htons((level1_int - 12) & 0xffff); } + // Patch ZeroScrap() for clipboard exchange with host OS + uint32 zero_scrap = find_rom_trap(0xa9fc); // ZeroScrap() + wp = (uint16 *)(ROMBaseHost + ZERO_SCRAP_PATCH_SPACE); + *wp++ = htons(M68K_EMUL_OP_ZERO_SCRAP); + *wp++ = htons(M68K_JMP); + *wp++ = htons((ROMBase + zero_scrap) >> 16); + *wp++ = htons((ROMBase + zero_scrap) & 0xffff); + base = ROMBase + ReadMacInt32(ROMBase + 0x22); + WriteMacInt32(base + 4 * (0xa9fc & 0x3ff), ZERO_SCRAP_PATCH_SPACE); + // Patch PutScrap() for clipboard exchange with host OS uint32 put_scrap = find_rom_trap(0xa9fe); // PutScrap() wp = (uint16 *)(ROMBaseHost + PUT_SCRAP_PATCH_SPACE); From 66ff591aa316b4a659dc408dae70e35dc5920677 Mon Sep 17 00:00:00 2001 From: Alexei Svitkine Date: Sat, 30 Jun 2012 22:23:27 -0400 Subject: [PATCH 05/12] more style fixes --- BasiliskII/src/MacOSX/clip_macosx64.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BasiliskII/src/MacOSX/clip_macosx64.mm b/BasiliskII/src/MacOSX/clip_macosx64.mm index 1d906a75..5f2760c8 100644 --- a/BasiliskII/src/MacOSX/clip_macosx64.mm +++ b/BasiliskII/src/MacOSX/clip_macosx64.mm @@ -386,7 +386,7 @@ static NSData *ConvertToMacTEXTAndStyl(NSAttributedString *aStr, NSData **outSty const NSUInteger charLimit = 32 * 1024; const NSUInteger elementLimit = 1601; - if([aStr length] > charLimit) { + if ([aStr length] > charLimit) { aStr = [aStr attributedSubstringFromRange:NSMakeRange(0, charLimit)]; } @@ -721,7 +721,7 @@ void GetScrap(void **handle, uint32 type, int32 offset) ZeroMacClipboard(); - if(stylData) + if (stylData) WriteDataToMacClipboard(stylData, TYPE_STYL); WriteDataToMacClipboard(textData, TYPE_TEXT); From fd78a64adee4f5a6bc9df8c096bdb379feba403a Mon Sep 17 00:00:00 2001 From: Alexei Svitkine Date: Sun, 1 Jul 2012 00:35:06 -0400 Subject: [PATCH 06/12] Fix 32-bit Mac OS X build. --- BasiliskII/src/MacOSX/clip_macosx.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/BasiliskII/src/MacOSX/clip_macosx.cpp b/BasiliskII/src/MacOSX/clip_macosx.cpp index 8ca71549..1d37edfc 100644 --- a/BasiliskII/src/MacOSX/clip_macosx.cpp +++ b/BasiliskII/src/MacOSX/clip_macosx.cpp @@ -159,6 +159,16 @@ void GetScrap(void **handle, uint32 type, int32 offset) #endif } +/* + * ZeroScrap() is called before a Mac application writes to the clipboard; clears out the previous contents + */ + +void ZeroScrap() +{ + D(bug("ZeroScrap\n")); + + we_put_this_data = false; +} /* * Mac application wrote to clipboard From 612761981f5034ace9a3dc132bc811290680eaf1 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Sat, 30 Jun 2012 22:54:06 -0500 Subject: [PATCH 07/12] dyngen: Don't leak already malloc'ed demangled_name --- SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c index 6565fea8..96ee805b 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c @@ -2885,8 +2885,10 @@ int gen_file(FILE *outfile, int out_type) char *demangled_name, *func_name; if ((demangled_name = malloc(nd)) == NULL) return -1; - if ((func_name = malloc(nf = nd)) == NULL) + if ((func_name = malloc(nf = nd)) == NULL) { + free(demangled_name); return -1; + } fprintf(outfile, "#ifndef DEFINE_CST\n"); fprintf(outfile, "#define DEFINE_CST(NAME, VALUE)\n"); From 668b8f14ba9da6c85aaeab1dd6743c08e55d1c3b Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Sat, 30 Jun 2012 22:48:46 -0500 Subject: [PATCH 08/12] dyngen: Don't leak func_name if realloc fails --- SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c | 28 +++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c index 96ee805b..880094ad 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c @@ -2937,20 +2937,22 @@ int gen_file(FILE *outfile, int out_type) demangled_name = cxx_demangle(name, demangled_name, &nd, &status); if (status == 0 && strstart(demangled_name, OP_PREFIX, NULL)) { /* get real function name */ - char *p = strchr(demangled_name, '('); - if (p && !strstart(p, "()::label", NULL)) { - int func_name_length = p - demangled_name; - if (nd > nf) { - nf = nd; - if ((func_name = realloc(func_name, nf)) == NULL) - return -1; - } - strncpy(func_name, demangled_name, func_name_length); - func_name[func_name_length] = '\0'; - /* emit code generator */ + char *p = strchr(demangled_name, '('); + if (p && !strstart(p, "()::label", NULL)) { + int func_name_length = p - demangled_name; + if (nd > nf) { + nf = nd; + if ((func_name = realloc(func_name, nf)) == NULL) { + free(func_name); + return -1; + } + } + strncpy(func_name, demangled_name, func_name_length); + func_name[func_name_length] = '\0'; + /* emit code generator */ #if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF) - if (sym->st_shndx != text_shndx) - error("invalid section for opcode (%s:0x%x)", name, sym->st_shndx); + if (sym->st_shndx != text_shndx) + error("invalid section for opcode (%s:0x%x)", name, sym->st_shndx); #endif gen_code(func_name, demangled_name, sym->st_value, sym->st_size, outfile, 3, NULL); } From a3a45f54e91434be41011963b287455518826ef8 Mon Sep 17 00:00:00 2001 From: Alexei Svitkine Date: Sun, 1 Jul 2012 13:48:09 -0400 Subject: [PATCH 09/12] dyngen: Don't leak func_name on realloc and fix indentation. --- SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c index 880094ad..549f5e2b 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c @@ -2941,11 +2941,13 @@ int gen_file(FILE *outfile, int out_type) if (p && !strstart(p, "()::label", NULL)) { int func_name_length = p - demangled_name; if (nd > nf) { + char *new_func_name; nf = nd; - if ((func_name = realloc(func_name, nf)) == NULL) { + if ((new_func_name = realloc(func_name, nf)) == NULL) { free(func_name); return -1; } + func_name = new_func_name; } strncpy(func_name, demangled_name, func_name_length); func_name[func_name_length] = '\0'; From 4d5ed807408b91038e504d14e91f48c124aaa34b Mon Sep 17 00:00:00 2001 From: Alexei Svitkine Date: Sun, 1 Jul 2012 13:52:45 -0400 Subject: [PATCH 10/12] dyngen: Fix more leaks. --- SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c index 549f5e2b..b6ead792 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c +++ b/SheepShaver/src/kpx_cpu/src/cpu/jit/dyngen.c @@ -885,8 +885,10 @@ int load_object(const char *filename, FILE *outfile) char *demangled_name, *func_name; if ((demangled_name = malloc(nd)) == NULL) return -1; - if ((func_name = malloc(nf = nd)) == NULL) + if ((func_name = malloc(nf = nd)) == NULL) { + free(demangled_name); return -1; + } for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name; @@ -914,6 +916,9 @@ int load_object(const char *filename, FILE *outfile) fprintf(outfile, "#endif\n"); } } + + free(func_name); + free(demangled_name); } return 0; } From a70f9b44f10df83d27b9ede66affd2ca39bab9aa Mon Sep 17 00:00:00 2001 From: Alexei Svitkine Date: Mon, 2 Jul 2012 00:40:08 -0400 Subject: [PATCH 11/12] Fix configure warning in BasiliskII's configure.ac too. --- BasiliskII/src/Unix/configure.ac | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/BasiliskII/src/Unix/configure.ac b/BasiliskII/src/Unix/configure.ac index ade33ec4..631064c7 100644 --- a/BasiliskII/src/Unix/configure.ac +++ b/BasiliskII/src/Unix/configure.ac @@ -1357,10 +1357,11 @@ if [[ "x$HAVE_GCC30" = "xyes" ]]; then CFLAGS="$CFLAGS -fno-strict-aliasing" AC_CACHE_CHECK([whether the compiler supports -fno-strict-aliasing], ac_cv_gcc_no_strict_aliasing, [ - AC_TRY_COMPILE([],[], - [ac_cv_gcc_no_strict_aliasing=yes; AC_SUBST(SLIRP_CFLAGS, "-fno-strict-aliasing")], - [ac_cv_gcc_no_strict_aliasing=no]) + AC_TRY_COMPILE([],[],[ac_cv_gcc_no_strict_aliasing=yes],[ac_cv_gcc_no_strict_aliasing=no]) ]) + if [[ "x$ac_cv_gcc_no_strict_aliasing" = "xyes" ]]; then + AC_SUBST(SLIRP_CFLAGS, "-fno-strict-aliasing") + fi CFLAGS="$SAVED_CFLAGS" fi From 42ae7000b5f94fa6748fd92e60b9f6c0511ada29 Mon Sep 17 00:00:00 2001 From: Alexei Svitkine Date: Mon, 2 Jul 2012 00:45:59 -0400 Subject: [PATCH 12/12] Use clip_macosx64.mm for BasiliskII 64-bit builds too. --- BasiliskII/src/Unix/configure.ac | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/BasiliskII/src/Unix/configure.ac b/BasiliskII/src/Unix/configure.ac index 631064c7..9b49d254 100644 --- a/BasiliskII/src/Unix/configure.ac +++ b/BasiliskII/src/Unix/configure.ac @@ -713,7 +713,18 @@ if [[ "x$WANT_SDL_VIDEO" = "xyes" ]]; then VIDEOSRCS="../SDL/video_sdl.cpp" KEYCODES="../SDL/keycodes" if [[ "x$ac_cv_framework_Carbon" = "xyes" ]]; then - EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx.cpp" + AC_MSG_CHECKING([whether __LP64__ is defined]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if !defined(__LP64__) + # error __LP64__ not defined + #endif + ]])], + [AC_MSG_RESULT(yes); LP64_DEFINED=yes], + [AC_MSG_RESULT(no)]) + if [[ "x$LP64_DEFINED" = "xyes" ]]; then + EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.mm" + else + EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx.cpp" + fi EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/utils_macosx.mm" CPPFLAGS="$CPPFLAGS -I../MacOSX" else