From 36195df44a442041185c729010a0c07bd7adead9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Fri, 25 Oct 2019 23:11:36 +0200 Subject: [PATCH 01/22] make window transparent --- BasiliskII/src/MacOSX/utils_macosx.mm | 34 +++++++++++++++++++++++++++ BasiliskII/src/SDL/video_sdl2.cpp | 5 ++++ 2 files changed, 39 insertions(+) diff --git a/BasiliskII/src/MacOSX/utils_macosx.mm b/BasiliskII/src/MacOSX/utils_macosx.mm index c68d2115..71ad1d3b 100644 --- a/BasiliskII/src/MacOSX/utils_macosx.mm +++ b/BasiliskII/src/MacOSX/utils_macosx.mm @@ -52,6 +52,40 @@ void disable_SDL2_macosx_menu_bar_keyboard_shortcuts() { } } +void make_window_transparent(SDL_Window * window) +{ + if (!window) { + return; + } + + SDL_SysWMinfo wmInfo; + SDL_VERSION(&wmInfo.version); + if (!SDL_GetWindowWMInfo(window, &wmInfo)) { + return; + } + + CGColorRef clearColor = [NSColor clearColor].CGColor; + NSWindow *cocoaWindow = wmInfo.info.cocoa.window; + NSView *sdlView = cocoaWindow.contentView; + sdlView.layer.backgroundColor = [NSColor clearColor].CGColor; + cocoaWindow.backgroundColor = [NSColor clearColor]; + cocoaWindow.hasShadow = NO; + cocoaWindow.opaque = NO; + + // make metal layer transparent + for (NSView *view in sdlView.subviews) { + if ([view.className isEqualToString:@"SDL_cocoametalview"]) { + view.layer.opaque = NO; + view.layer.backgroundColor = clearColor; + return; + } + } + + // make OpenGL surface transparent + GLint zero = 0; + [[NSOpenGLContext currentContext] setValues:&zero forParameter:NSOpenGLCPSurfaceOpacity]; +} + bool is_fullscreen_osx(SDL_Window * window) { if (!window) { diff --git a/BasiliskII/src/SDL/video_sdl2.cpp b/BasiliskII/src/SDL/video_sdl2.cpp index 42247b21..86520abf 100644 --- a/BasiliskII/src/SDL/video_sdl2.cpp +++ b/BasiliskII/src/SDL/video_sdl2.cpp @@ -751,6 +751,11 @@ static SDL_Surface * init_sdl_video(int width, int height, int bpp, Uint32 flags } if (flags & SDL_WINDOW_FULLSCREEN) SDL_SetWindowGrab(sdl_window, SDL_TRUE); +#ifdef __MACOSX__ + extern void make_window_transparent(SDL_Window * window); + make_window_transparent(sdl_window); +#endif + // Some SDL events (regarding some native-window events), need processing // as they are generated. SDL2 has a facility, SDL_AddEventWatch(), which // allows events to be processed as they are generated. From 5be50d7959004cff54c303d8666f24e4b3c42c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Sun, 27 Oct 2019 16:59:20 +0100 Subject: [PATCH 02/22] rootless: mask out non-window regions --- .../BasiliskII.xcodeproj/project.pbxproj | 4 + BasiliskII/src/MacOSX/config.h | 1 + BasiliskII/src/SDL/prefs_sdl.cpp | 3 + BasiliskII/src/SDL/video_rootless.cpp | 201 ++++++++++++++++++ BasiliskII/src/SDL/video_sdl2.cpp | 21 +- BasiliskII/src/rom_patches.cpp | 5 + 6 files changed, 232 insertions(+), 3 deletions(-) create mode 100644 BasiliskII/src/SDL/video_rootless.cpp diff --git a/BasiliskII/src/MacOSX/BasiliskII.xcodeproj/project.pbxproj b/BasiliskII/src/MacOSX/BasiliskII.xcodeproj/project.pbxproj index 70b59a66..ef79fa0d 100644 --- a/BasiliskII/src/MacOSX/BasiliskII.xcodeproj/project.pbxproj +++ b/BasiliskII/src/MacOSX/BasiliskII.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 28EFB21E2364DB4F00988A5B /* video_rootless.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28EFB21C2364DB4F00988A5B /* video_rootless.cpp */; }; 752F26F91F240E51001032B4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 752F26F81F240E51001032B4 /* Foundation.framework */; }; 752F26FB1F240E69001032B4 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 752F26FA1F240E69001032B4 /* IOKit.framework */; }; 752F27011F242BAF001032B4 /* prefs_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 752F27001F242BAF001032B4 /* prefs_sdl.cpp */; }; @@ -202,6 +203,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 28EFB21C2364DB4F00988A5B /* video_rootless.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = video_rootless.cpp; sourceTree = ""; }; 752F26F81F240E51001032B4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 752F26FA1F240E69001032B4 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 752F27001F242BAF001032B4 /* prefs_sdl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = prefs_sdl.cpp; sourceTree = ""; }; @@ -661,6 +663,7 @@ 75CBCF761F5DB65E00830063 /* video_sdl.cpp */, 75CBCF741F5DB3AD00830063 /* video_sdl2.cpp */, 752F27021F242F51001032B4 /* xpram_sdl.cpp */, + 28EFB21C2364DB4F00988A5B /* video_rootless.cpp */, ); name = SDL; path = ../SDL; @@ -1124,6 +1127,7 @@ 752F27011F242BAF001032B4 /* prefs_sdl.cpp in Sources */, 7539E2971F23C5FD006B2DF2 /* newcpu.cpp in Sources */, 7539E12A1F23B25A006B2DF2 /* vm_alloc.cpp in Sources */, + 28EFB21E2364DB4F00988A5B /* video_rootless.cpp in Sources */, E413D93220D260BC00E437D8 /* if.c in Sources */, 7539E16C1F23B25A006B2DF2 /* main.cpp in Sources */, 7539E26D1F23B32A006B2DF2 /* strlcpy.c in Sources */, diff --git a/BasiliskII/src/MacOSX/config.h b/BasiliskII/src/MacOSX/config.h index cb14154b..0a2375dc 100644 --- a/BasiliskII/src/MacOSX/config.h +++ b/BasiliskII/src/MacOSX/config.h @@ -821,5 +821,6 @@ #define X86_64_ASSEMBLY #define OPTIMIZED_FLAGS #define FPU_IEEE +#define VIDEO_ROOTLESS #endif diff --git a/BasiliskII/src/SDL/prefs_sdl.cpp b/BasiliskII/src/SDL/prefs_sdl.cpp index 5151f760..8dd64a79 100644 --- a/BasiliskII/src/SDL/prefs_sdl.cpp +++ b/BasiliskII/src/SDL/prefs_sdl.cpp @@ -32,6 +32,9 @@ prefs_desc platform_prefs_items[] = { {"idlewait", TYPE_BOOLEAN, false, "sleep when idle"}, {"sdlrender", TYPE_STRING, false, "SDL_Renderer driver (\"auto\", \"software\" (may be faster), etc.)"}, +#ifdef VIDEO_ROOTLESS + {"rootless", TYPE_BOOLEAN, false, "Rootles mode (System 7)"}, +#endif {NULL, TYPE_END, false} // End of list }; diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp new file mode 100644 index 00000000..d7d30b04 --- /dev/null +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -0,0 +1,201 @@ +// +// video_rootless.cpp +// BasiliskII +// +// Created by Jesús A. Álvarez on 26/10/2019. +// + +#include +#include "sysdeps.h" +#include "cpu_emulation.h" +#include "main.h" +#include "macos_util.h" +#include "prefs.h" + +/* + * Rootless mode support + */ + +static const uint8 rootless_proc[] = { + // PEntryFromProcessSerialNumber(GetNextProcess(d0:d1)) + // returns next PSN in d0:d1, PEntryPtr in d2 + 0x2F, 0x01, // move.l d1,-(sp) ; psn low + 0x2F, 0x00, // move.l d0,-(sp) ; psn high + 0x55, 0x4F, // suba.w #2,sp ; result + 0x48, 0x6F, 0x00, 0x02, // pea 2(sp) ; ptr(psn) + 0x3F, 0x3C, 0x00, 0x38, // move.w #$38,-(sp) ; GetNextProcess + 0xA8, 0x8F, // _OSDispatch ; get psn of first process + 0x30, 0x1F, // move.w (sp)+,d0 ; result + + 0x59, 0x4F, // subq #4,sp ; result + 0x48, 0x6F, 0x00, 0x04, // pea 4(sp) ; ptr(psn) + 0x3F, 0x3C, 0x00, 0x4F, // move.w #$4F,-(sp) ; _PEntryFromProcessSerialNumber + 0xA8, 0x8F, // _OSDispatch ; get PEntry + 0x24, 0x1F, // move.l (sp)+, d2 ; pEntry + 0x20, 0x1F, // move.l (sp)+, d0 ; psn high + 0x22, 0x1F, // move.l (sp)+, d1 ; psn low + 0x4E, 0x75, // rts +}; + +static uint32 rootless_proc_ptr = 0; + +void InstallRootlessProc() { + // Rootless mode support + M68kRegisters r; + if (PrefsFindBool("rootless")) { + r.d[0] = sizeof(rootless_proc); + Execute68kTrap(0xa71e, &r); // NewPtrSysClear() + rootless_proc_ptr = r.a[0]; + printf("Installing rootless support: 0x%x\n", rootless_proc_ptr); + Host2Mac_memcpy(rootless_proc_ptr, rootless_proc, sizeof(rootless_proc)); + } else { + rootless_proc_ptr = 0; + } +} + +static struct { + uint8_t *pixels; + int w,h; +} display_mask = { + .pixels = NULL, + .w = 0, + .h = 0 +}; + +void MaskRect(int16 top, int16 left, int16 bottom, int16 right, bool in) { + if (top < 0) top = 0; + if (left < 0) left = 0; + + uint8_t *line = display_mask.pixels + display_mask.w * top + left; + for (int y = top; y < bottom; y++) { + memset(line, in ? 0xff : 0x00, right - left); + line += display_mask.w; + } +} + +void PrintRegion(uint32 regionPtr) { + int16 size = ReadMacInt16(regionPtr); + int16 top = ReadMacInt16(regionPtr + 2); + int16 left = ReadMacInt16(regionPtr + 4); + int16 bottom = ReadMacInt16(regionPtr + 6); + int16 right = ReadMacInt16(regionPtr + 8); + printf("Region (%d: %d,%d %dx%d):\n", size, left, top, (right-left), (bottom-top)); + for(int i=0; i < size; i++) { + printf("%02x", ReadMacInt8(regionPtr + i)); + } + printf("\n"); +} + +void MaskRegion(uint32 regionPtr, bool in) { + // https://www.info-mac.org/viewtopic.php?t=17328 + uint16 size = ReadMacInt16(regionPtr); + int16 top = ReadMacInt16(regionPtr + 2); + int16 left = ReadMacInt16(regionPtr + 4); + int16 bottom = ReadMacInt16(regionPtr + 6); + int16 right = ReadMacInt16(regionPtr + 8); + + if (size == 10) { + MaskRect(top, left, bottom, right, in); + return; + } + + uint8_t *scanline = display_mask.pixels + top * display_mask.w; + uint8_t *curLine = (uint8*)alloca(display_mask.w); + memset(curLine, 0, display_mask.w); + + uint32 ptr = regionPtr + 10; + for (int16 y = top; y < bottom; y++) { + uint16 nextLine = ReadMacInt16(ptr); + if (nextLine == y) { + // apply changes to current line + ptr += 2; + for(;;) { + uint16 begin = ReadMacInt16(ptr); + ptr += 2; + if (begin == 0x7fff) break; + uint16 end = ReadMacInt16(ptr); + ptr += 2; + for (int i=begin; i < end; i++) { + curLine[i] ^= 1; + } + } + } + + // blit current line + if (in) { + for (int x = left; x < right; x++) { + scanline[x] |= curLine[x]; + } + } else { + for (int x = left; x < right; x++) { + scanline[x] |= !curLine[x]; + } + } + + scanline += display_mask.w; + } +} + +void update_display_mask(int w, int h) { + if (rootless_proc_ptr == 0) { + return; + } + + uint32 expandMem = ReadMacInt32(0x02B6); + uint16 emProcessMgrExists = ReadMacInt16(expandMem + 0x0128); + if (!emProcessMgrExists) { + return; + } + + if (display_mask.w != w || display_mask.h != h) { + // new mask + free(display_mask.pixels); + display_mask.pixels = (uint8_t*)calloc(1, w*h); + display_mask.w = w; + display_mask.h = h; + } + + // clear all + memset(display_mask.pixels, 0, display_mask.w * display_mask.h); + + // hide desktop + uint32 deskPort = ReadMacInt32(0x9E2); + uint32 deskPortVisRgn = ReadMacInt32(ReadMacInt32(deskPort + 0x18)); + MaskRegion(deskPortVisRgn, false); + + // show menu bar + uint16 menuBarHeight = ReadMacInt16(0x0BAA); + MaskRect(0, 0, menuBarHeight, display_mask.w, true); +} + +void apply_display_mask(SDL_Surface * host_surface, SDL_Rect update_rect) { + if (display_mask.pixels == NULL) { + return; + } + + printf("apply video mask (%d,%d->%dx%d)\n", (int)update_rect.x, (int)update_rect.y, (int)update_rect.w, (int)update_rect.h); + + if (host_surface->format->format != SDL_PIXELFORMAT_ARGB8888) { + printf("Invalid host surface\n"); + return; + } + + uint32_t * srcPixels = (uint32_t*)((uint8_t *)host_surface->pixels + + update_rect.y * host_surface->pitch + + update_rect.x * 4); + + uint8_t * srcMask = display_mask.pixels + update_rect.y * display_mask.w + update_rect.x; + for (int y = update_rect.y; y < update_rect.y+update_rect.h; y++) { + uint32_t * pixel = srcPixels; + uint8_t * mask = srcMask; + for (int x = update_rect.x; x < update_rect.x+update_rect.w; x++) { + if (*mask == 0) { + *pixel = 0; + } + pixel++; + mask++; + } + srcPixels += host_surface->pitch / 4; + srcMask += display_mask.w; + } +} diff --git a/BasiliskII/src/SDL/video_sdl2.cpp b/BasiliskII/src/SDL/video_sdl2.cpp index 86520abf..37b2e586 100644 --- a/BasiliskII/src/SDL/video_sdl2.cpp +++ b/BasiliskII/src/SDL/video_sdl2.cpp @@ -65,6 +65,12 @@ #include "video_blit.h" #include "vm_alloc.h" +#ifdef VIDEO_ROOTLESS +extern void make_window_transparent(SDL_Window * window); +extern void update_display_mask(int w, int h); +extern void apply_display_mask(SDL_Surface * host_surface, SDL_Rect update_rect); +#endif + #define DEBUG 0 #include "debug.h" @@ -751,9 +757,10 @@ static SDL_Surface * init_sdl_video(int width, int height, int bpp, Uint32 flags } if (flags & SDL_WINDOW_FULLSCREEN) SDL_SetWindowGrab(sdl_window, SDL_TRUE); -#ifdef __MACOSX__ - extern void make_window_transparent(SDL_Window * window); - make_window_transparent(sdl_window); +#ifdef VIDEO_ROOTLESS + if (PrefsFindBool("rootless")) { + make_window_transparent(sdl_window); + } #endif // Some SDL events (regarding some native-window events), need processing @@ -899,6 +906,11 @@ static int present_sdl_video() } UNLOCK_PALETTE; // passed potential deadlock, can unlock palette +#ifdef VIDEO_ROOTLESS + // Apply mask + apply_display_mask(host_surface, sdl_update_video_rect); +#endif + // Update the host OS' texture void * srcPixels = (void *)((uint8_t *)host_surface->pixels + sdl_update_video_rect.y * host_surface->pitch + @@ -1702,6 +1714,9 @@ void VideoInterrupt(void) if (toggle_fullscreen) do_toggle_fullscreen(); +#ifdef VIDEO_ROOTLESS + update_display_mask(host_surface->w, host_surface->h); +#endif present_sdl_video(); // Temporarily give up frame buffer lock (this is the point where diff --git a/BasiliskII/src/rom_patches.cpp b/BasiliskII/src/rom_patches.cpp index fdedf5e2..0d051c79 100644 --- a/BasiliskII/src/rom_patches.cpp +++ b/BasiliskII/src/rom_patches.cpp @@ -754,6 +754,11 @@ void InstallDrivers(uint32 pb) r.a[0] = pb; Execute68kTrap(0xa000, &r); // Open() } + +#ifdef VIDEO_ROOTLESS + extern void InstallRootlessProc(void); + InstallRootlessProc(); +#endif } From 035bc98cbca0e0ea2c017de257b37a553ff86b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Wed, 30 Oct 2019 23:46:33 +0100 Subject: [PATCH 03/22] rootless: mask menus --- BasiliskII/src/SDL/video_rootless.cpp | 128 +++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 3 deletions(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index d7d30b04..f3449a5b 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -35,6 +35,20 @@ static const uint8 rootless_proc[] = { 0x20, 0x1F, // move.l (sp)+, d0 ; psn high 0x22, 0x1F, // move.l (sp)+, d1 ; psn low 0x4E, 0x75, // rts + + // a0 = GetResource(d0, d1) +#define GETRESOURCE 38 // offset to this function + 0x59, 0x4F, // subq #4,sp ; result + 0x2F, 0x00, // move.l d0,-(sp) ; type + 0x3F, 0x01, // move.w d1,-(sp) ; size + 0xA9, 0xA0, // _GetResource + 0x20, 0x57, // movea.l (sp),a0 ; result to a0 + 0x59, 0x4F, // subq #4, sp ; result + 0x2F, 0x08, // move.l a0,-(sp) ; handle + 0xA9, 0xA5, // _SizeRsrc + 0x20, 0x1F, // move.l (sp)+,d0 ; size + 0x20, 0x5F, // movea.l (sp)+,a0 ; handle + 0x4E, 0x75, // rts }; static uint32 rootless_proc_ptr = 0; @@ -63,6 +77,7 @@ static struct { }; void MaskRect(int16 top, int16 left, int16 bottom, int16 right, bool in) { + if (top == bottom || left == right) return; if (top < 0) top = 0; if (left < 0) left = 0; @@ -136,17 +151,112 @@ void MaskRegion(uint32 regionPtr, bool in) { } } +static uint32 low_mem_map = 0; + +uint32 GetLowMemOffset(uint32 addr) { + if (low_mem_map == 0) { + abort(); + } + + uint32 offset = 0; + uint32 ptr = low_mem_map; + for(;;) { + uint16 size = ReadMacInt16(ptr); + if (size == 0) break; + uint32 lo = ReadMacInt32(ptr+2); + ptr += 6; + if (addr < lo) { + return UINT32_MAX; + } else if (addr < (lo+size)) { + return offset + (addr-lo); + } + offset += size; + } + return UINT32_MAX; +} + +static uint32 GetResource(uint32 type, int16 id, int32* size) { + M68kRegisters r; + r.d[0] = type; + r.d[1] = id; + Execute68k(rootless_proc_ptr + GETRESOURCE, &r); + if (size) { + *size = r.d[0]; + } + return r.a[0]; +} + +static void MaskMenuBar() { + uint16 menuBarHeight = ReadMacInt16(0x0BAA); + MaskRect(0, 0, menuBarHeight, display_mask.w, true); +} + +static void MaskMenu(uint32 mbEntry) { + int16 menuTop = ReadMacInt16(mbEntry); + int16 menuLeft = ReadMacInt16(mbEntry + 2); + int16 menuBottom = ReadMacInt16(mbEntry + 4); + int16 menuRight = ReadMacInt16(mbEntry + 6); + MaskRect(menuTop, menuLeft-1, menuBottom+1, menuRight+1, true); + // shadow + MaskRect(menuBottom+1, menuLeft+1, menuBottom+2, menuRight+1, true); + MaskRect(menuTop+2, menuRight+1, menuBottom+2, menuRight+2, true); +} + +uint16 menuEntries[16]; +uint16 *lastMenuEntry = menuEntries; + +static void MaskMenus(uint32 expandMem, uint32 lowMemPtr) { + uint32 emHelpGlobals = ReadMacInt32(expandMem + 0x78); + uint16 inMenuSelect = ReadMacInt16(emHelpGlobals + 0x11c); + if (!inMenuSelect) { + // clean up + lastMenuEntry = menuEntries; + *lastMenuEntry = 0; + return; + } + + uint32 mbSaveLoc = ReadMacInt32(ReadMacInt32(lowMemPtr + GetLowMemOffset(0x0B5C))); + if (mbSaveLoc == 0) { + // no menu yet + return; + } + + uint16 mbEntryOffset = ReadMacInt16(mbSaveLoc); + if (lastMenuEntry == menuEntries && *lastMenuEntry == 0) { + // first menu + *lastMenuEntry = mbEntryOffset; + } else if (mbEntryOffset > *lastMenuEntry) { + // added menu + *(++lastMenuEntry) = mbEntryOffset; + } else if (mbEntryOffset < *lastMenuEntry) { + // removed menu + lastMenuEntry--; + } + + // mask all menus + for (uint16 *entry = menuEntries; entry <= lastMenuEntry; entry++) { + MaskMenu(mbSaveLoc + *entry); + } +} + void update_display_mask(int w, int h) { if (rootless_proc_ptr == 0) { return; } + // Check for process manager uint32 expandMem = ReadMacInt32(0x02B6); uint16 emProcessMgrExists = ReadMacInt16(expandMem + 0x0128); if (!emProcessMgrExists) { return; } + // Read lowmem mapping + if (low_mem_map == 0) { + uint32 handle = GetResource('lmem', -16458, NULL); + low_mem_map = ReadMacInt32(handle); + } + if (display_mask.w != w || display_mask.h != h) { // new mask free(display_mask.pixels); @@ -163,9 +273,21 @@ void update_display_mask(int w, int h) { uint32 deskPortVisRgn = ReadMacInt32(ReadMacInt32(deskPort + 0x18)); MaskRegion(deskPortVisRgn, false); - // show menu bar - uint16 menuBarHeight = ReadMacInt16(0x0BAA); - MaskRect(0, 0, menuBarHeight, display_mask.w, true); + MaskMenuBar(); + + M68kRegisters r; + // Find frontmost process + for(r.d[0] = 0, r.d[1] = 0;;) { + Execute68k(rootless_proc_ptr, &r); + uint32_t pEntryPtr = r.d[2]; + if (r.d[2] == 0) break; + + uint16 state = ReadMacInt16(pEntryPtr); + if (state != 4) break; + + uint32 lowMemPtr = ReadMacInt32(ReadMacInt32(pEntryPtr + 0x9E)); + MaskMenus(expandMem, lowMemPtr); + } } void apply_display_mask(SDL_Surface * host_surface, SDL_Rect update_rect) { From fef996ed2fe7ae52686140ae62957274a4bad281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Fri, 1 Nov 2019 19:33:28 +0100 Subject: [PATCH 04/22] rootless: reset low_mem_map on start --- BasiliskII/src/SDL/video_rootless.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index f3449a5b..b7284000 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -52,6 +52,7 @@ static const uint8 rootless_proc[] = { }; static uint32 rootless_proc_ptr = 0; +static uint32 low_mem_map = 0; void InstallRootlessProc() { // Rootless mode support @@ -62,6 +63,7 @@ void InstallRootlessProc() { rootless_proc_ptr = r.a[0]; printf("Installing rootless support: 0x%x\n", rootless_proc_ptr); Host2Mac_memcpy(rootless_proc_ptr, rootless_proc, sizeof(rootless_proc)); + low_mem_map = 0; } else { rootless_proc_ptr = 0; } @@ -151,8 +153,6 @@ void MaskRegion(uint32 regionPtr, bool in) { } } -static uint32 low_mem_map = 0; - uint32 GetLowMemOffset(uint32 addr) { if (low_mem_map == 0) { abort(); From fa827b5c2ac4a57985c0a078931728b4c8ea08e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Sat, 2 Nov 2019 23:56:11 +0100 Subject: [PATCH 05/22] install rootless code when opening video driver --- BasiliskII/src/SDL/video_rootless.cpp | 10 ++++++++-- BasiliskII/src/rom_patches.cpp | 5 ----- BasiliskII/src/video.cpp | 6 ++++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index b7284000..5913d1f9 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -54,19 +54,25 @@ static const uint8 rootless_proc[] = { static uint32 rootless_proc_ptr = 0; static uint32 low_mem_map = 0; -void InstallRootlessProc() { +int16 InstallRootlessProc() { // Rootless mode support M68kRegisters r; if (PrefsFindBool("rootless")) { + printf("Installing rootless support\n"); r.d[0] = sizeof(rootless_proc); Execute68kTrap(0xa71e, &r); // NewPtrSysClear() + if (r.a[0] == 0) { + return memFullErr; + } rootless_proc_ptr = r.a[0]; - printf("Installing rootless support: 0x%x\n", rootless_proc_ptr); Host2Mac_memcpy(rootless_proc_ptr, rootless_proc, sizeof(rootless_proc)); low_mem_map = 0; + printf("Installed at 0x%x\n", rootless_proc_ptr); } else { rootless_proc_ptr = 0; + low_mem_map = 0; } + return noErr; } static struct { diff --git a/BasiliskII/src/rom_patches.cpp b/BasiliskII/src/rom_patches.cpp index 0d051c79..fdedf5e2 100644 --- a/BasiliskII/src/rom_patches.cpp +++ b/BasiliskII/src/rom_patches.cpp @@ -754,11 +754,6 @@ void InstallDrivers(uint32 pb) r.a[0] = pb; Execute68kTrap(0xa000, &r); // Open() } - -#ifdef VIDEO_ROOTLESS - extern void InstallRootlessProc(void); - InstallRootlessProc(); -#endif } diff --git a/BasiliskII/src/video.cpp b/BasiliskII/src/video.cpp index 3b46864e..dd9310f5 100644 --- a/BasiliskII/src/video.cpp +++ b/BasiliskII/src/video.cpp @@ -482,6 +482,12 @@ int16 monitor_desc::driver_open(void) // Init color palette (solid gray) set_gray_palette(); + + // Enable rootless video +#ifdef VIDEO_ROOTLESS + extern int16 InstallRootlessProc(void); + return InstallRootlessProc(); +#endif return noErr; } From ddaf33ba43b3f3ae4982f2d8e79da70400451636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Mon, 4 Nov 2019 23:09:41 +0100 Subject: [PATCH 06/22] make non-window regions click-through --- .../BasiliskII.xcodeproj/project.pbxproj | 4 + BasiliskII/src/MacOSX/utils_macosx.mm | 19 +++ BasiliskII/src/SDL/video_rootless.cpp | 139 ++++++++++++++++-- BasiliskII/src/SDL/video_sdl2.cpp | 10 +- 4 files changed, 156 insertions(+), 16 deletions(-) diff --git a/BasiliskII/src/MacOSX/BasiliskII.xcodeproj/project.pbxproj b/BasiliskII/src/MacOSX/BasiliskII.xcodeproj/project.pbxproj index ef79fa0d..ab24d7bf 100644 --- a/BasiliskII/src/MacOSX/BasiliskII.xcodeproj/project.pbxproj +++ b/BasiliskII/src/MacOSX/BasiliskII.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 28EFB21E2364DB4F00988A5B /* video_rootless.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28EFB21C2364DB4F00988A5B /* video_rootless.cpp */; }; + 28EFB222236CE16F00988A5B /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28EFB221236CE16F00988A5B /* QuartzCore.framework */; }; 752F26F91F240E51001032B4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 752F26F81F240E51001032B4 /* Foundation.framework */; }; 752F26FB1F240E69001032B4 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 752F26FA1F240E69001032B4 /* IOKit.framework */; }; 752F27011F242BAF001032B4 /* prefs_sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 752F27001F242BAF001032B4 /* prefs_sdl.cpp */; }; @@ -204,6 +205,7 @@ /* Begin PBXFileReference section */ 28EFB21C2364DB4F00988A5B /* video_rootless.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = video_rootless.cpp; sourceTree = ""; }; + 28EFB221236CE16F00988A5B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 752F26F81F240E51001032B4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 752F26FA1F240E69001032B4 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 752F27001F242BAF001032B4 /* prefs_sdl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = prefs_sdl.cpp; sourceTree = ""; }; @@ -445,6 +447,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 28EFB222236CE16F00988A5B /* QuartzCore.framework in Frameworks */, E413D93620D260DA00E437D8 /* SDL2.framework in Frameworks */, 756C1B391F25306A00620917 /* AppKit.framework in Frameworks */, 752F26FB1F240E69001032B4 /* IOKit.framework in Frameworks */, @@ -514,6 +517,7 @@ 752F26F71F240E51001032B4 /* Frameworks */ = { isa = PBXGroup; children = ( + 28EFB221236CE16F00988A5B /* QuartzCore.framework */, E413D93520D260DA00E437D8 /* SDL2.framework */, 756C1B381F25306A00620917 /* AppKit.framework */, 752F26FA1F240E69001032B4 /* IOKit.framework */, diff --git a/BasiliskII/src/MacOSX/utils_macosx.mm b/BasiliskII/src/MacOSX/utils_macosx.mm index 71ad1d3b..da43f523 100644 --- a/BasiliskII/src/MacOSX/utils_macosx.mm +++ b/BasiliskII/src/MacOSX/utils_macosx.mm @@ -19,9 +19,12 @@ */ #include +#include +#include #include "sysdeps.h" #include "utils_macosx.h" #include +#include #if SDL_VERSION_ATLEAST(2,0,0) #include @@ -68,6 +71,9 @@ void make_window_transparent(SDL_Window * window) NSWindow *cocoaWindow = wmInfo.info.cocoa.window; NSView *sdlView = cocoaWindow.contentView; sdlView.layer.backgroundColor = [NSColor clearColor].CGColor; + CALayer *maskLayer = [CAShapeLayer layer]; + sdlView.layer.mask = [maskLayer retain]; + SDL_SetWindowData(window, "maskLayer", maskLayer); cocoaWindow.backgroundColor = [NSColor clearColor]; cocoaWindow.hasShadow = NO; cocoaWindow.opaque = NO; @@ -86,6 +92,19 @@ void make_window_transparent(SDL_Window * window) [[NSOpenGLContext currentContext] setValues:&zero forParameter:NSOpenGLCPSurfaceOpacity]; } +void update_window_mask_rects(SDL_Window * window, int h, const std::vector &rects) +{ + CAShapeLayer *maskLayer = (CAShapeLayer*)SDL_GetWindowData(window, "maskLayer"); + CGMutablePathRef path = CGPathCreateMutable(); + for(auto it = rects.begin(); it != rects.end(); ++it) { + SDL_Rect rect = *it; + CGPathAddRect(path, NULL, CGRectMake(rect.x, rect.y, rect.w, rect.h)); + } + maskLayer.path = path; + maskLayer.affineTransform = CGAffineTransformScale(CGAffineTransformMakeTranslation(0, h), 1.0, -1.0); + CGPathRelease(path); +} + bool is_fullscreen_osx(SDL_Window * window) { if (!window) { diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index 5913d1f9..97f8b51a 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -11,6 +11,7 @@ #include "main.h" #include "macos_util.h" #include "prefs.h" +#include /* * Rootless mode support @@ -139,7 +140,7 @@ void MaskRegion(uint32 regionPtr, bool in) { uint16 end = ReadMacInt16(ptr); ptr += 2; for (int i=begin; i < end; i++) { - curLine[i] ^= 1; + curLine[i] ^= 0xff; } } } @@ -151,7 +152,7 @@ void MaskRegion(uint32 regionPtr, bool in) { } } else { for (int x = left; x < right; x++) { - scanline[x] |= !curLine[x]; + scanline[x] |= ~curLine[x]; } } @@ -159,6 +160,14 @@ void MaskRegion(uint32 regionPtr, bool in) { } } +SDL_Rect GetRegionBounds(uint32 regionPtr) { + int16 top = ReadMacInt16(regionPtr + 2); + int16 left = ReadMacInt16(regionPtr + 4); + int16 bottom = ReadMacInt16(regionPtr + 6); + int16 right = ReadMacInt16(regionPtr + 8); + return (SDL_Rect){.x = left, .y = top, .w = right-left, .h = bottom-top}; +} + uint32 GetLowMemOffset(uint32 addr) { if (low_mem_map == 0) { abort(); @@ -192,12 +201,13 @@ static uint32 GetResource(uint32 type, int16 id, int32* size) { return r.a[0]; } -static void MaskMenuBar() { +static SDL_Rect MaskMenuBar() { uint16 menuBarHeight = ReadMacInt16(0x0BAA); MaskRect(0, 0, menuBarHeight, display_mask.w, true); + return (SDL_Rect){.x = 0, .y = 0, .w = display_mask.w, .h = menuBarHeight}; } -static void MaskMenu(uint32 mbEntry) { +static SDL_Rect MaskMenu(uint32 mbEntry) { int16 menuTop = ReadMacInt16(mbEntry); int16 menuLeft = ReadMacInt16(mbEntry + 2); int16 menuBottom = ReadMacInt16(mbEntry + 4); @@ -206,12 +216,13 @@ static void MaskMenu(uint32 mbEntry) { // shadow MaskRect(menuBottom+1, menuLeft+1, menuBottom+2, menuRight+1, true); MaskRect(menuTop+2, menuRight+1, menuBottom+2, menuRight+2, true); + return (SDL_Rect){.x = menuLeft-1, .y = menuTop, .w = menuRight - menuLeft + 3, .h = menuBottom - menuTop + 2}; } uint16 menuEntries[16]; uint16 *lastMenuEntry = menuEntries; -static void MaskMenus(uint32 expandMem, uint32 lowMemPtr) { +static void MaskMenus(uint32 expandMem, uint32 lowMemPtr, std::vector &rects) { uint32 emHelpGlobals = ReadMacInt32(expandMem + 0x78); uint16 inMenuSelect = ReadMacInt16(emHelpGlobals + 0x11c); if (!inMenuSelect) { @@ -241,11 +252,76 @@ static void MaskMenus(uint32 expandMem, uint32 lowMemPtr) { // mask all menus for (uint16 *entry = menuEntries; entry <= lastMenuEntry; entry++) { - MaskMenu(mbSaveLoc + *entry); + rects.push_back(MaskMenu(mbSaveLoc + *entry)); } } -void update_display_mask(int w, int h) { +static void MaskBits(int16 x, int16 y, uint16 bits) { + uint16 testBit = 0x8000; + for(int i=0; i < 16; i++, testBit >>= 1) { + if (x < 0 || y < 0 || y >= display_mask.h) continue; + display_mask.pixels[x + (y * display_mask.w) + i] |= (bits & testBit) ? 0xff : 0x00; + } +} + +bool cursor_point_opaque() { + if (display_mask.pixels == NULL) { + return true; + } + int32 my = ReadMacInt16(0x0828); + int32 mx = ReadMacInt16(0x082a); + return display_mask.pixels[mx + my * display_mask.w]; +} + +static SDL_Rect MaskCursor() { + int32 y = ReadMacInt16(0x0830); + int32 x = ReadMacInt16(0x0832); + // cursor data + uint16 *TheCrsr = (uint16*)Mac2HostAddr(0x0844); + // hotspot + uint16 hx = ntohs(TheCrsr[32]); + uint16 hy = ntohs(TheCrsr[33]); + + // apply mask + for (int i=0; i < 16; i++) { + MaskBits(x-hx, y+i-hy, ntohs(TheCrsr[16+i])); + } + return (SDL_Rect){.x=x-hx, .y=y-hy, .w=16, .h=16}; +} + +bool IsLayer(uint32 windowPtr) { + return ReadMacInt16(windowPtr + 0x4A) == 0xDEAD; +} + +void WalkLayerHierarchy(uint32 layerPtr, int level, std::vector &mask_rects) { + if (layerPtr == 0) return; + int kind = ReadMacInt16(layerPtr + 0x6C); + int visible = ReadMacInt8(layerPtr + 0x6E); + bool isLayer = IsLayer(layerPtr); + uint32 strucRgnHandle = ReadMacInt32(layerPtr + 0x72); + int x = 0,y = 0,w = 0,h = 0; + if (strucRgnHandle) { + uint32 regionPtr = ReadMacInt32(strucRgnHandle); + y = ReadMacInt16(regionPtr + 2); + x = ReadMacInt16(regionPtr + 4); + h = ReadMacInt16(regionPtr + 6) - y; + w = ReadMacInt16(regionPtr + 8) - x; + if (visible && w && h && !isLayer) { + mask_rects.push_back(GetRegionBounds(regionPtr)); + } + } + //printf("%*s%s 0x%x, kind=%d, visible=%d, %d,%d %dx%d\n", 2*level, "", IsLayer(layerPtr) ? "Layer" : "Window", layerPtr, kind, visible, x,y,w,h); + + if (IsLayer(layerPtr)) { + uint32 subWindows = ReadMacInt32(layerPtr + 0x94); + WalkLayerHierarchy(subWindows, level+1, mask_rects); + } + + uint32 nextWindow = ReadMacInt32(layerPtr + 0x90); + if (nextWindow) WalkLayerHierarchy(nextWindow, level, mask_rects); +} + +void update_display_mask(SDL_Window *window, int w, int h) { if (rootless_proc_ptr == 0) { return; } @@ -261,12 +337,13 @@ void update_display_mask(int w, int h) { if (low_mem_map == 0) { uint32 handle = GetResource('lmem', -16458, NULL); low_mem_map = ReadMacInt32(handle); + printf("low_mem_map at 0x%x\n", low_mem_map); } if (display_mask.w != w || display_mask.h != h) { // new mask free(display_mask.pixels); - display_mask.pixels = (uint8_t*)calloc(1, w*h); + display_mask.pixels = (uint8_t*)calloc(1, w*h*2); display_mask.w = w; display_mask.h = h; } @@ -279,20 +356,54 @@ void update_display_mask(int w, int h) { uint32 deskPortVisRgn = ReadMacInt32(ReadMacInt32(deskPort + 0x18)); MaskRegion(deskPortVisRgn, false); - MaskMenuBar(); + bool has_front_process = false; + std::vector mask_rects; + mask_rects.push_back(MaskMenuBar()); M68kRegisters r; - // Find frontmost process + uint32 rootLayerPtr = 0; for(r.d[0] = 0, r.d[1] = 0;;) { Execute68k(rootless_proc_ptr, &r); uint32_t pEntryPtr = r.d[2]; if (r.d[2] == 0) break; uint16 state = ReadMacInt16(pEntryPtr); - if (state != 4) break; + if (state == 4) { + has_front_process = true; + uint32 lowMemPtr = ReadMacInt32(ReadMacInt32(pEntryPtr + 0x9E)); + if (lowMemPtr) { + MaskMenus(expandMem, lowMemPtr, mask_rects); + } + } - uint32 lowMemPtr = ReadMacInt32(ReadMacInt32(pEntryPtr + 0x9E)); - MaskMenus(expandMem, lowMemPtr); + uint32 layerPtr = ReadMacInt32(pEntryPtr + 0x70); + uint16 layerTxSize = ReadMacInt16(layerPtr + 0x4A); + if (layerTxSize != 0xDEAD) { + // not a layer + continue; + } + + // find root layer + if (rootLayerPtr == 0) { + rootLayerPtr = ReadMacInt32(layerPtr + 0x82); // parent layer + while (ReadMacInt32(rootLayerPtr + 0x82)) { + rootLayerPtr = ReadMacInt32(rootLayerPtr + 0x82); + } + WalkLayerHierarchy(rootLayerPtr, 0, mask_rects); + } + } + + // Cursor + if (cursor_point_opaque()) { + SDL_ShowCursor(SDL_DISABLE); + mask_rects.push_back(MaskCursor()); + } else { + SDL_ShowCursor(SDL_ENABLE); + } + + extern void update_window_mask_rects(SDL_Window * window, int h, const std::vector &rects); + if (has_front_process) { + update_window_mask_rects(window, display_mask.h, mask_rects); } } @@ -301,7 +412,7 @@ void apply_display_mask(SDL_Surface * host_surface, SDL_Rect update_rect) { return; } - printf("apply video mask (%d,%d->%dx%d)\n", (int)update_rect.x, (int)update_rect.y, (int)update_rect.w, (int)update_rect.h); + //printf("apply video mask (%d,%d->%dx%d)\n", (int)update_rect.x, (int)update_rect.y, (int)update_rect.w, (int)update_rect.h); if (host_surface->format->format != SDL_PIXELFORMAT_ARGB8888) { printf("Invalid host surface\n"); diff --git a/BasiliskII/src/SDL/video_sdl2.cpp b/BasiliskII/src/SDL/video_sdl2.cpp index 37b2e586..1586d560 100644 --- a/BasiliskII/src/SDL/video_sdl2.cpp +++ b/BasiliskII/src/SDL/video_sdl2.cpp @@ -67,8 +67,9 @@ #ifdef VIDEO_ROOTLESS extern void make_window_transparent(SDL_Window * window); -extern void update_display_mask(int w, int h); +extern void update_display_mask(SDL_Window * window, int w, int h); extern void apply_display_mask(SDL_Surface * host_surface, SDL_Rect update_rect); +extern bool cursor_point_opaque(void); #endif #define DEBUG 0 @@ -1715,7 +1716,7 @@ void VideoInterrupt(void) do_toggle_fullscreen(); #ifdef VIDEO_ROOTLESS - update_display_mask(host_surface->w, host_surface->h); + update_display_mask(sdl_window, host_surface->w, host_surface->h); #endif present_sdl_video(); @@ -2182,6 +2183,11 @@ static void handle_events(void) // Mouse button case SDL_MOUSEBUTTONDOWN: { +#ifdef VIDEO_ROOTLESS + if (!cursor_point_opaque()) { + break; + } +#endif unsigned int button = event.button.button; if (button == SDL_BUTTON_LEFT) ADBMouseDown(0); From 0aaefd89f35cc3cc8196e2080ca6527caa107601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Mon, 4 Nov 2019 23:47:14 +0100 Subject: [PATCH 07/22] mask pop-up menus --- BasiliskII/src/SDL/video_rootless.cpp | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index 97f8b51a..dd2a7a28 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -201,43 +201,41 @@ static uint32 GetResource(uint32 type, int16 id, int32* size) { return r.a[0]; } -static SDL_Rect MaskMenuBar() { - uint16 menuBarHeight = ReadMacInt16(0x0BAA); - MaskRect(0, 0, menuBarHeight, display_mask.w, true); - return (SDL_Rect){.x = 0, .y = 0, .w = display_mask.w, .h = menuBarHeight}; -} - static SDL_Rect MaskMenu(uint32 mbEntry) { int16 menuTop = ReadMacInt16(mbEntry); int16 menuLeft = ReadMacInt16(mbEntry + 2); int16 menuBottom = ReadMacInt16(mbEntry + 4); int16 menuRight = ReadMacInt16(mbEntry + 6); - MaskRect(menuTop, menuLeft-1, menuBottom+1, menuRight+1, true); + MaskRect(menuTop-1, menuLeft-1, menuBottom+1, menuRight+1, true); // shadow MaskRect(menuBottom+1, menuLeft+1, menuBottom+2, menuRight+1, true); MaskRect(menuTop+2, menuRight+1, menuBottom+2, menuRight+2, true); - return (SDL_Rect){.x = menuLeft-1, .y = menuTop, .w = menuRight - menuLeft + 3, .h = menuBottom - menuTop + 2}; + return (SDL_Rect){.x = menuLeft-1, .y = menuTop-1, .w = menuRight - menuLeft + 3, .h = menuBottom - menuTop + 2}; } uint16 menuEntries[16]; uint16 *lastMenuEntry = menuEntries; +uint16 menuBarHeight; +bool inMenuSelect = false; + +static SDL_Rect MaskMenuBar() { + if (!inMenuSelect) { + menuBarHeight = ReadMacInt16(0x0BAA); + } + MaskRect(0, 0, menuBarHeight, display_mask.w, true); + return (SDL_Rect){.x = 0, .y = 0, .w = display_mask.w, .h = menuBarHeight}; +} static void MaskMenus(uint32 expandMem, uint32 lowMemPtr, std::vector &rects) { - uint32 emHelpGlobals = ReadMacInt32(expandMem + 0x78); - uint16 inMenuSelect = ReadMacInt16(emHelpGlobals + 0x11c); - if (!inMenuSelect) { - // clean up - lastMenuEntry = menuEntries; - *lastMenuEntry = 0; - return; - } - uint32 mbSaveLoc = ReadMacInt32(ReadMacInt32(lowMemPtr + GetLowMemOffset(0x0B5C))); if (mbSaveLoc == 0) { // no menu yet + inMenuSelect = false; return; } + inMenuSelect = true; + uint16 mbEntryOffset = ReadMacInt16(mbSaveLoc); if (lastMenuEntry == menuEntries && *lastMenuEntry == 0) { // first menu @@ -351,14 +349,13 @@ void update_display_mask(SDL_Window *window, int w, int h) { // clear all memset(display_mask.pixels, 0, display_mask.w * display_mask.h); - // hide desktop + // show non-desktop uint32 deskPort = ReadMacInt32(0x9E2); uint32 deskPortVisRgn = ReadMacInt32(ReadMacInt32(deskPort + 0x18)); MaskRegion(deskPortVisRgn, false); bool has_front_process = false; std::vector mask_rects; - mask_rects.push_back(MaskMenuBar()); M68kRegisters r; uint32 rootLayerPtr = 0; @@ -393,6 +390,9 @@ void update_display_mask(SDL_Window *window, int w, int h) { } } + // Menu Bar + mask_rects.push_back(MaskMenuBar()); + // Cursor if (cursor_point_opaque()) { SDL_ShowCursor(SDL_DISABLE); From f81ca7897a4d4dfa3c9d9ed42681db333a1d1676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Mon, 4 Nov 2019 23:48:09 +0100 Subject: [PATCH 08/22] double-buffer cursor mask this prevents clicks being wrongfully ignored during mask recalculation --- BasiliskII/src/SDL/video_rootless.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index dd2a7a28..35572474 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -78,9 +78,11 @@ int16 InstallRootlessProc() { static struct { uint8_t *pixels; + uint8_t *cursorMask; int w,h; } display_mask = { .pixels = NULL, + .cursorMask = NULL, .w = 0, .h = 0 }; @@ -268,7 +270,7 @@ bool cursor_point_opaque() { } int32 my = ReadMacInt16(0x0828); int32 mx = ReadMacInt16(0x082a); - return display_mask.pixels[mx + my * display_mask.w]; + return display_mask.cursorMask[mx + my * display_mask.w]; } static SDL_Rect MaskCursor() { @@ -342,6 +344,7 @@ void update_display_mask(SDL_Window *window, int w, int h) { // new mask free(display_mask.pixels); display_mask.pixels = (uint8_t*)calloc(1, w*h*2); + display_mask.cursorMask = &display_mask.pixels[display_mask.w * display_mask.h]; display_mask.w = w; display_mask.h = h; } @@ -393,6 +396,9 @@ void update_display_mask(SDL_Window *window, int w, int h) { // Menu Bar mask_rects.push_back(MaskMenuBar()); + // Copy over cursor mask + memcpy(display_mask.cursorMask, display_mask.pixels, display_mask.w * display_mask.h); + // Cursor if (cursor_point_opaque()) { SDL_ShowCursor(SDL_DISABLE); From f995962795c45a7b77d8ef0e7e757b948599a997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Tue, 5 Nov 2019 21:35:03 +0100 Subject: [PATCH 09/22] reuse existing mask layer --- BasiliskII/src/MacOSX/utils_macosx.mm | 8 +++++--- BasiliskII/src/SDL/video_rootless.cpp | 20 +++++++++++++++----- BasiliskII/src/SDL/video_sdl2.cpp | 7 ------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/BasiliskII/src/MacOSX/utils_macosx.mm b/BasiliskII/src/MacOSX/utils_macosx.mm index da43f523..c2716c0e 100644 --- a/BasiliskII/src/MacOSX/utils_macosx.mm +++ b/BasiliskII/src/MacOSX/utils_macosx.mm @@ -71,9 +71,11 @@ void make_window_transparent(SDL_Window * window) NSWindow *cocoaWindow = wmInfo.info.cocoa.window; NSView *sdlView = cocoaWindow.contentView; sdlView.layer.backgroundColor = [NSColor clearColor].CGColor; - CALayer *maskLayer = [CAShapeLayer layer]; - sdlView.layer.mask = [maskLayer retain]; - SDL_SetWindowData(window, "maskLayer", maskLayer); + if (SDL_GetWindowData(window, "maskLayer") == NULL) { + CALayer *maskLayer = [CAShapeLayer layer]; + sdlView.layer.mask = maskLayer; + SDL_SetWindowData(window, "maskLayer", maskLayer); + } cocoaWindow.backgroundColor = [NSColor clearColor]; cocoaWindow.hasShadow = NO; cocoaWindow.opaque = NO; diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index 35572474..08774f95 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -13,6 +13,9 @@ #include "prefs.h" #include +extern void make_window_transparent(SDL_Window * window); +extern void update_sdl_video(SDL_Surface *s, int numrects, SDL_Rect *rects); + /* * Rootless mode support */ @@ -340,13 +343,23 @@ void update_display_mask(SDL_Window *window, int w, int h) { printf("low_mem_map at 0x%x\n", low_mem_map); } + std::vector mask_rects; + if (display_mask.w != w || display_mask.h != h) { // new mask free(display_mask.pixels); - display_mask.pixels = (uint8_t*)calloc(1, w*h*2); - display_mask.cursorMask = &display_mask.pixels[display_mask.w * display_mask.h]; + display_mask.pixels = (uint8_t*)calloc(2, w*h); display_mask.w = w; display_mask.h = h; + display_mask.cursorMask = &display_mask.pixels[display_mask.w * display_mask.h]; + + // update whole screen + make_window_transparent(window); + SDL_Rect rect = {.x = 0, .y = 0, .w = w, .h = h}; + update_sdl_video(NULL, 1, &rect); + mask_rects.push_back(rect); + memset(display_mask.pixels, 0xff, 2 * display_mask.w * display_mask.h); + return; } // clear all @@ -358,7 +371,6 @@ void update_display_mask(SDL_Window *window, int w, int h) { MaskRegion(deskPortVisRgn, false); bool has_front_process = false; - std::vector mask_rects; M68kRegisters r; uint32 rootLayerPtr = 0; @@ -418,8 +430,6 @@ void apply_display_mask(SDL_Surface * host_surface, SDL_Rect update_rect) { return; } - //printf("apply video mask (%d,%d->%dx%d)\n", (int)update_rect.x, (int)update_rect.y, (int)update_rect.w, (int)update_rect.h); - if (host_surface->format->format != SDL_PIXELFORMAT_ARGB8888) { printf("Invalid host surface\n"); return; diff --git a/BasiliskII/src/SDL/video_sdl2.cpp b/BasiliskII/src/SDL/video_sdl2.cpp index 1586d560..2e8f1302 100644 --- a/BasiliskII/src/SDL/video_sdl2.cpp +++ b/BasiliskII/src/SDL/video_sdl2.cpp @@ -66,7 +66,6 @@ #include "vm_alloc.h" #ifdef VIDEO_ROOTLESS -extern void make_window_transparent(SDL_Window * window); extern void update_display_mask(SDL_Window * window, int w, int h); extern void apply_display_mask(SDL_Surface * host_surface, SDL_Rect update_rect); extern bool cursor_point_opaque(void); @@ -757,12 +756,6 @@ static SDL_Surface * init_sdl_video(int width, int height, int bpp, Uint32 flags } } if (flags & SDL_WINDOW_FULLSCREEN) SDL_SetWindowGrab(sdl_window, SDL_TRUE); - -#ifdef VIDEO_ROOTLESS - if (PrefsFindBool("rootless")) { - make_window_transparent(sdl_window); - } -#endif // Some SDL events (regarding some native-window events), need processing // as they are generated. SDL2 has a facility, SDL_AddEventWatch(), which From f32c6b66e07ef5ee658bb2508eaa2a083173893f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Tue, 5 Nov 2019 21:49:41 +0100 Subject: [PATCH 10/22] clamp masking to screen size --- BasiliskII/src/SDL/video_rootless.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index 08774f95..35e03138 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -94,6 +94,8 @@ void MaskRect(int16 top, int16 left, int16 bottom, int16 right, bool in) { if (top == bottom || left == right) return; if (top < 0) top = 0; if (left < 0) left = 0; + if (bottom > display_mask.h) bottom = display_mask.h; + if (right > display_mask.w) right = display_mask.w; uint8_t *line = display_mask.pixels + display_mask.w * top + left; for (int y = top; y < bottom; y++) { @@ -122,7 +124,9 @@ void MaskRegion(uint32 regionPtr, bool in) { int16 left = ReadMacInt16(regionPtr + 4); int16 bottom = ReadMacInt16(regionPtr + 6); int16 right = ReadMacInt16(regionPtr + 8); - + if (bottom > display_mask.h) bottom = display_mask.h; + if (right > display_mask.w) right = display_mask.w; + if (size == 10) { MaskRect(top, left, bottom, right, in); return; @@ -144,6 +148,9 @@ void MaskRegion(uint32 regionPtr, bool in) { if (begin == 0x7fff) break; uint16 end = ReadMacInt16(ptr); ptr += 2; + if (end > display_mask.w) { + end = display_mask.w; + } for (int i=begin; i < end; i++) { curLine[i] ^= 0xff; } From 6f453b61842b4050e0998bfe1a9f7540814e87d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Tue, 5 Nov 2019 21:50:02 +0100 Subject: [PATCH 11/22] fix menu masking --- BasiliskII/src/SDL/video_rootless.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index 35e03138..7c209efb 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -246,13 +246,14 @@ static void MaskMenus(uint32 expandMem, uint32 lowMemPtr, std::vector return; } - inMenuSelect = true; - uint16 mbEntryOffset = ReadMacInt16(mbSaveLoc); - if (lastMenuEntry == menuEntries && *lastMenuEntry == 0) { + if (mbEntryOffset == 0) { + inMenuSelect = false; + return; + } else if (lastMenuEntry == menuEntries && *lastMenuEntry == 0) { // first menu *lastMenuEntry = mbEntryOffset; - } else if (mbEntryOffset > *lastMenuEntry) { + } else if (mbEntryOffset > *lastMenuEntry && lastMenuEntry < &menuEntries[16]) { // added menu *(++lastMenuEntry) = mbEntryOffset; } else if (mbEntryOffset < *lastMenuEntry) { @@ -260,6 +261,8 @@ static void MaskMenus(uint32 expandMem, uint32 lowMemPtr, std::vector lastMenuEntry--; } + inMenuSelect = true; + // mask all menus for (uint16 *entry = menuEntries; entry <= lastMenuEntry; entry++) { rects.push_back(MaskMenu(mbSaveLoc + *entry)); From bcbaecae128f559d160ac418e45a2a8c39354ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Tue, 5 Nov 2019 22:07:02 +0100 Subject: [PATCH 12/22] update mask rects when no front process is found --- BasiliskII/src/SDL/video_rootless.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index 7c209efb..525ca7b5 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -430,9 +430,7 @@ void update_display_mask(SDL_Window *window, int w, int h) { } extern void update_window_mask_rects(SDL_Window * window, int h, const std::vector &rects); - if (has_front_process) { - update_window_mask_rects(window, display_mask.h, mask_rects); - } + update_window_mask_rects(window, display_mask.h, mask_rects); } void apply_display_mask(SDL_Surface * host_surface, SDL_Rect update_rect) { From cd70c9925e03073046896e295613e1ad43a478fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Tue, 5 Nov 2019 22:07:27 +0100 Subject: [PATCH 13/22] make video opaque by default --- BasiliskII/src/CrossPlatform/video_blit.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BasiliskII/src/CrossPlatform/video_blit.cpp b/BasiliskII/src/CrossPlatform/video_blit.cpp index 5f1a0ae3..b0da9593 100755 --- a/BasiliskII/src/CrossPlatform/video_blit.cpp +++ b/BasiliskII/src/CrossPlatform/video_blit.cpp @@ -245,7 +245,8 @@ static void Blit_Copy_Raw(uint8 * dest, const uint8 * source, uint32 length) (dst = (((src) >> 24) & UVAL64(0x000000ff000000ff)) | \ (((src) >> 8) & UVAL64(0x0000ff000000ff00)) | \ (((src) & UVAL64(0x0000ff000000ff00)) << 8) | \ - (((src) & UVAL64(0x000000ff000000ff)) << 24)) + (((src) & UVAL64(0x000000ff000000ff)) << 24) | \ + (UVAL64(0xff000000ff000000))) #define FB_DEPTH 24 #include "video_blit.h" From f6616d1d4d7f1b9f8be95ec294357a884e6d1266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Tue, 5 Nov 2019 23:02:14 +0100 Subject: [PATCH 14/22] add rootless as video mode instead of own setting --- BasiliskII/src/SDL/prefs_sdl.cpp | 3 --- BasiliskII/src/SDL/video_rootless.cpp | 2 +- BasiliskII/src/SDL/video_sdl2.cpp | 22 ++++++++++++++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/BasiliskII/src/SDL/prefs_sdl.cpp b/BasiliskII/src/SDL/prefs_sdl.cpp index 8dd64a79..5151f760 100644 --- a/BasiliskII/src/SDL/prefs_sdl.cpp +++ b/BasiliskII/src/SDL/prefs_sdl.cpp @@ -32,9 +32,6 @@ prefs_desc platform_prefs_items[] = { {"idlewait", TYPE_BOOLEAN, false, "sleep when idle"}, {"sdlrender", TYPE_STRING, false, "SDL_Renderer driver (\"auto\", \"software\" (may be faster), etc.)"}, -#ifdef VIDEO_ROOTLESS - {"rootless", TYPE_BOOLEAN, false, "Rootles mode (System 7)"}, -#endif {NULL, TYPE_END, false} // End of list }; diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index 525ca7b5..2f30d305 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -61,7 +61,7 @@ static uint32 low_mem_map = 0; int16 InstallRootlessProc() { // Rootless mode support M68kRegisters r; - if (PrefsFindBool("rootless")) { + if (strncmp(PrefsFindString("screen"), "rootless", 8) == 0) { printf("Installing rootless support\n"); r.d[0] = sizeof(rootless_proc); Execute68kTrap(0xa71e, &r); // NewPtrSysClear() diff --git a/BasiliskII/src/SDL/video_sdl2.cpp b/BasiliskII/src/SDL/video_sdl2.cpp index 2e8f1302..e0947b56 100644 --- a/BasiliskII/src/SDL/video_sdl2.cpp +++ b/BasiliskII/src/SDL/video_sdl2.cpp @@ -88,7 +88,8 @@ extern int display_type; // See enum above #else enum { DISPLAY_WINDOW, // windowed display - DISPLAY_SCREEN // fullscreen display + DISPLAY_SCREEN, // fullscreen display + DISPLAY_ROOTLESS // fullscreen with transparent desktop }; static int display_type = DISPLAY_WINDOW; // See enum above #endif @@ -743,6 +744,11 @@ static SDL_Surface * init_sdl_video(int width, int height, int bpp, Uint32 flags window_flags |= SDL_WINDOW_RESIZABLE; */ if (!sdl_window) { +#ifdef VIDEO_ROOTLESS + if (display_type == DISPLAY_ROOTLESS) { + window_flags |= SDL_WINDOW_BORDERLESS; + } +#endif sdl_window = SDL_CreateWindow( "Basilisk II", SDL_WINDOWPOS_UNDEFINED, @@ -1380,6 +1386,13 @@ bool VideoInit(bool classic) display_type = DISPLAY_WINDOW; else if (sscanf(mode_str, "dga/%d/%d", &default_width, &default_height) == 2) display_type = DISPLAY_SCREEN; +#ifdef VIDEO_ROOTLESS + else if (strncmp(mode_str, "rootless", 8) == 0) { + display_type = DISPLAY_ROOTLESS; + default_width = sdl_display_width(); + default_height = sdl_display_height(); + } +#endif } if (default_width <= 0) default_width = sdl_display_width(); @@ -1469,7 +1482,12 @@ bool VideoInit(bool classic) for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++) add_mode(display_type, w, h, video_modes[i].resolution_id, TrivialBytesPerRow(w, (video_depth)d), d); } - } +#ifdef VIDEO_ROOTLESS + } else if (display_type == DISPLAY_ROOTLESS) { + for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++) + add_mode(display_type, default_width, default_height, 0x80, TrivialBytesPerRow(default_width, (video_depth)d), d); +#endif + } if (VideoModes.empty()) { ErrorAlert(STR_NO_XVISUAL_ERR); From 68fcaa117bdcf543a85335b603cefbf5b9927f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Tue, 5 Nov 2019 23:02:59 +0100 Subject: [PATCH 15/22] make rootless window overlay everything else --- BasiliskII/src/MacOSX/utils_macosx.mm | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/BasiliskII/src/MacOSX/utils_macosx.mm b/BasiliskII/src/MacOSX/utils_macosx.mm index c2716c0e..68855488 100644 --- a/BasiliskII/src/MacOSX/utils_macosx.mm +++ b/BasiliskII/src/MacOSX/utils_macosx.mm @@ -75,10 +75,26 @@ void make_window_transparent(SDL_Window * window) CALayer *maskLayer = [CAShapeLayer layer]; sdlView.layer.mask = maskLayer; SDL_SetWindowData(window, "maskLayer", maskLayer); + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserverForName:NSWindowDidBecomeKeyNotification object:cocoaWindow queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { + NSWindow *window = (NSWindow*)note.object; + window.level = NSMainMenuWindowLevel+1; + }]; + [nc addObserverForName:NSWindowDidResignKeyNotification object:cocoaWindow queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { + NSWindow *window = (NSWindow*)note.object; + // hack for window to be sent behind new key window + [window setIsVisible:NO]; + [window setLevel:NSNormalWindowLevel]; + [window setIsVisible:YES]; + }]; } cocoaWindow.backgroundColor = [NSColor clearColor]; cocoaWindow.hasShadow = NO; cocoaWindow.opaque = NO; + if (cocoaWindow.isKeyWindow) { + cocoaWindow.level = NSMainMenuWindowLevel+1; + } // make metal layer transparent for (NSView *view in sdlView.subviews) { From 93797ff488c794bf58dbb720b0db3de89fd8c924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Wed, 6 Nov 2019 21:12:29 +0100 Subject: [PATCH 16/22] embiggen menu bar to host's size --- BasiliskII/src/MacOSX/utils_macosx.mm | 3 +++ BasiliskII/src/SDL/video_rootless.cpp | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/BasiliskII/src/MacOSX/utils_macosx.mm b/BasiliskII/src/MacOSX/utils_macosx.mm index 68855488..55dd4a85 100644 --- a/BasiliskII/src/MacOSX/utils_macosx.mm +++ b/BasiliskII/src/MacOSX/utils_macosx.mm @@ -61,6 +61,9 @@ void make_window_transparent(SDL_Window * window) return; } + extern int native_menubar_size; + native_menubar_size = (int)[[NSApp mainMenu] menuBarHeight]; + SDL_SysWMinfo wmInfo; SDL_VERSION(&wmInfo.version); if (!SDL_GetWindowWMInfo(window, &wmInfo)) { diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index 2f30d305..40718a0f 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -15,6 +15,7 @@ extern void make_window_transparent(SDL_Window * window); extern void update_sdl_video(SDL_Surface *s, int numrects, SDL_Rect *rects); +int native_menubar_size = 0; /* * Rootless mode support @@ -231,6 +232,10 @@ uint16 menuBarHeight; bool inMenuSelect = false; static SDL_Rect MaskMenuBar() { + if (native_menubar_size && ReadMacInt16(0x0BAA) == 20) { + // Embiggen menubar + WriteMacInt16(0xBAA, native_menubar_size); + } if (!inMenuSelect) { menuBarHeight = ReadMacInt16(0x0BAA); } From aa95b9a11da679992850d31434fb72a3645e18ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Wed, 6 Nov 2019 23:46:35 +0100 Subject: [PATCH 17/22] mask window outlines when dragging --- BasiliskII/src/SDL/video_rootless.cpp | 49 +++++++++++++++++++++++++++ BasiliskII/src/emul_op.cpp | 10 ++++++ BasiliskII/src/include/emul_op.h | 4 ++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index 40718a0f..fc4815f7 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -11,6 +11,7 @@ #include "main.h" #include "macos_util.h" #include "prefs.h" +#include "emul_op.h" #include extern void make_window_transparent(SDL_Window * window); @@ -54,10 +55,34 @@ static const uint8 rootless_proc[] = { 0x20, 0x1F, // move.l (sp)+,d0 ; size 0x20, 0x5F, // movea.l (sp)+,a0 ; handle 0x4E, 0x75, // rts + +#define PAINTRGNPATCH (GETRESOURCE + 22) + M68K_EMUL_OP_PAINTRGN >> 8, + M68K_EMUL_OP_PAINTRGN & 0xff, + 0x2F, 0x3C, 0, 0, 0, 0, // move.l address, -(sp) + 0x4E, 0x75, // rts + +#define DRAGGRAYRGNPATCH (PAINTRGNPATCH + 10) + M68K_EMUL_OP_DRAGGRAYRGN >> 8, + M68K_EMUL_OP_DRAGGRAYRGN & 0xff, + 0x2F, 0x3C, 0, 0, 0, 0, // move.l address, -(sp) + 0x4E, 0x75, // rts }; static uint32 rootless_proc_ptr = 0; static uint32 low_mem_map = 0; +static bool dragging_region = false; +static uint32 drag_region_ptr = 0; + +static void MyPatchTrap(int trap, uint32 ptr) { + M68kRegisters r; + r.d[0] = trap; + Execute68kTrap(0xa746, &r); // GetToolTrapAddress() + WriteMacInt32(ptr + 4, r.a[0]); + r.d[0] = trap; + r.a[0] = ptr; + Execute68kTrap(0xa647, &r); // SetToolTrap() +} int16 InstallRootlessProc() { // Rootless mode support @@ -73,6 +98,10 @@ int16 InstallRootlessProc() { Host2Mac_memcpy(rootless_proc_ptr, rootless_proc, sizeof(rootless_proc)); low_mem_map = 0; printf("Installed at 0x%x\n", rootless_proc_ptr); + + // Install patches to detect dragging regions + MyPatchTrap(0xa8d3, rootless_proc_ptr + PAINTRGNPATCH); + MyPatchTrap(0xa905, rootless_proc_ptr + DRAGGRAYRGNPATCH); } else { rootless_proc_ptr = 0; low_mem_map = 0; @@ -423,6 +452,16 @@ void update_display_mask(SDL_Window *window, int w, int h) { // Menu Bar mask_rects.push_back(MaskMenuBar()); + // Drag region + int8 mouseState = ReadMacInt8(0x0172); + if (dragging_region && mouseState) { + dragging_region = false; + drag_region_ptr = 0; + } else if (dragging_region && !mouseState && drag_region_ptr) { + MaskRegion(drag_region_ptr, true); + mask_rects.push_back(GetRegionBounds(drag_region_ptr)); + } + // Copy over cursor mask memcpy(display_mask.cursorMask, display_mask.pixels, display_mask.w * display_mask.h); @@ -467,3 +506,13 @@ void apply_display_mask(SDL_Surface * host_surface, SDL_Rect update_rect) { srcMask += display_mask.w; } } + +void check_drag_region(M68kRegisters *r, uint16 opcode) { + if (opcode == M68K_EMUL_OP_DRAGGRAYRGN) { + dragging_region = true; + drag_region_ptr = 0; + } else if (opcode == M68K_EMUL_OP_PAINTRGN && dragging_region) { + uint32 regionHandle = ReadMacInt32(r->a[7]+4); + drag_region_ptr = ReadMacInt32(regionHandle); + } +} diff --git a/BasiliskII/src/emul_op.cpp b/BasiliskII/src/emul_op.cpp index bdab4f63..bd5acd61 100644 --- a/BasiliskII/src/emul_op.cpp +++ b/BasiliskII/src/emul_op.cpp @@ -580,6 +580,16 @@ void EmulOp(uint16 opcode, M68kRegisters *r) #endif break; } + +#ifdef VIDEO_ROOTLESS + case M68K_EMUL_OP_PAINTRGN: + case M68K_EMUL_OP_DRAGGRAYRGN: { + // Patched traps for tracking dragged outlines + extern void check_drag_region(M68kRegisters *r, uint16 opcode); + check_drag_region(r, opcode); + break; + } +#endif default: printf("FATAL: EMUL_OP called with bogus opcode %08x\n", opcode); diff --git a/BasiliskII/src/include/emul_op.h b/BasiliskII/src/include/emul_op.h index e7684127..eb98e391 100644 --- a/BasiliskII/src/include/emul_op.h +++ b/BasiliskII/src/include/emul_op.h @@ -90,7 +90,9 @@ enum { M68K_EMUL_OP_SOUNDIN_CLOSE, M68K_EMUL_OP_DEBUGUTIL, M68K_EMUL_OP_IDLE_TIME, - M68K_EMUL_OP_SUSPEND, + M68K_EMUL_OP_SUSPEND, // 0x7138 + M68K_EMUL_OP_PAINTRGN, + M68K_EMUL_OP_DRAGGRAYRGN, M68K_EMUL_OP_MAX // highest number }; From 60ce4fc5f7dc5d62b5ed6fb641414e8ea5370409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Thu, 7 Nov 2019 23:46:08 +0100 Subject: [PATCH 18/22] fix menu shadows --- BasiliskII/src/SDL/video_rootless.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index fc4815f7..f8a10275 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -252,7 +252,7 @@ static SDL_Rect MaskMenu(uint32 mbEntry) { // shadow MaskRect(menuBottom+1, menuLeft+1, menuBottom+2, menuRight+1, true); MaskRect(menuTop+2, menuRight+1, menuBottom+2, menuRight+2, true); - return (SDL_Rect){.x = menuLeft-1, .y = menuTop-1, .w = menuRight - menuLeft + 3, .h = menuBottom - menuTop + 2}; + return (SDL_Rect){.x = menuLeft-1, .y = menuTop-1, .w = menuRight - menuLeft + 3, .h = menuBottom - menuTop + 3}; } uint16 menuEntries[16]; From 20f027dd97728e4ef571882cf98fa5e83be96559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Sat, 9 Nov 2019 22:50:57 +0100 Subject: [PATCH 19/22] don't add window observers multiple times --- BasiliskII/src/MacOSX/utils_macosx.mm | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/BasiliskII/src/MacOSX/utils_macosx.mm b/BasiliskII/src/MacOSX/utils_macosx.mm index 55dd4a85..b2c66798 100644 --- a/BasiliskII/src/MacOSX/utils_macosx.mm +++ b/BasiliskII/src/MacOSX/utils_macosx.mm @@ -74,11 +74,7 @@ void make_window_transparent(SDL_Window * window) NSWindow *cocoaWindow = wmInfo.info.cocoa.window; NSView *sdlView = cocoaWindow.contentView; sdlView.layer.backgroundColor = [NSColor clearColor].CGColor; - if (SDL_GetWindowData(window, "maskLayer") == NULL) { - CALayer *maskLayer = [CAShapeLayer layer]; - sdlView.layer.mask = maskLayer; - SDL_SetWindowData(window, "maskLayer", maskLayer); - + if (SDL_GetWindowData(window, "observing") == NULL) { NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserverForName:NSWindowDidBecomeKeyNotification object:cocoaWindow queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { NSWindow *window = (NSWindow*)note.object; @@ -91,6 +87,12 @@ void make_window_transparent(SDL_Window * window) [window setLevel:NSNormalWindowLevel]; [window setIsVisible:YES]; }]; + SDL_SetWindowData(window, "observing", nc); + } + if (SDL_GetWindowData(window, "maskLayer") == NULL) { + CALayer *maskLayer = [CAShapeLayer layer]; + sdlView.layer.mask = maskLayer; + SDL_SetWindowData(window, "maskLayer", maskLayer); } cocoaWindow.backgroundColor = [NSColor clearColor]; cocoaWindow.hasShadow = NO; From 369c45a0b0b7cb5e266f45223605c50190e293a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Thu, 28 Feb 2019 20:12:35 +0100 Subject: [PATCH 20/22] use SDL scancode instead of sym --- BasiliskII/src/SDL/video_sdl2.cpp | 139 ++++-------------------------- 1 file changed, 19 insertions(+), 120 deletions(-) diff --git a/BasiliskII/src/SDL/video_sdl2.cpp b/BasiliskII/src/SDL/video_sdl2.cpp index e0947b56..a514baec 100644 --- a/BasiliskII/src/SDL/video_sdl2.cpp +++ b/BasiliskII/src/SDL/video_sdl2.cpp @@ -1963,132 +1963,31 @@ static bool is_hotkey_down(SDL_Keysym const & ks) static int kc_decode(SDL_Keysym const & ks, bool key_down) { + static int8_t usb_to_adb_scancode[] = { + -1, -1, -1, -1, 0, 11, 8, 2, 14, 3, 5, 4, 34, 38, 40, 37, + 46, 45, 31, 35, 12, 15, 1, 17, 32, 9, 13, 7, 16, 6, 18, 19, + 20, 21, 23, 22, 26, 28, 25, 29, 36, 53, 51, 48, 49, 27, 24, 33, + 30, 42, 42, 41, 39, 10, 43, 47, 44, 57, 122, 120, 99, 118, 96, 97, + 98, 100, 101, 109, 103, 111, 105, 107, 113, 114, 115, 116, 117, 119, 121, 60, + 59, 61, 62, 71, 75, 67, 78, 69, 76, 83, 84, 85, 86, 87, 88, 89, + 91, 92, 82, 65, 50, 55, 126, 81, 105, 107, 113, 106, 64, 79, 80, 90, + -1, -1, -1, -1, -1, 114, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, + 72, 73, -1, -1, -1, 95, -1, 94, -1, 93, -1, -1, -1, -1, -1, -1, + 104, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 54, 56, 58, 55, 54, 56, 58, 55, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; switch (ks.sym) { - case SDLK_a: return 0x00; - case SDLK_b: return 0x0b; - case SDLK_c: return 0x08; - case SDLK_d: return 0x02; - case SDLK_e: return 0x0e; - case SDLK_f: return 0x03; - case SDLK_g: return 0x05; - case SDLK_h: return 0x04; - case SDLK_i: return 0x22; - case SDLK_j: return 0x26; - case SDLK_k: return 0x28; - case SDLK_l: return 0x25; - case SDLK_m: return 0x2e; - case SDLK_n: return 0x2d; - case SDLK_o: return 0x1f; - case SDLK_p: return 0x23; - case SDLK_q: return 0x0c; - case SDLK_r: return 0x0f; - case SDLK_s: return 0x01; - case SDLK_t: return 0x11; - case SDLK_u: return 0x20; - case SDLK_v: return 0x09; - case SDLK_w: return 0x0d; - case SDLK_x: return 0x07; - case SDLK_y: return 0x10; - case SDLK_z: return 0x06; - - case SDLK_1: case SDLK_EXCLAIM: return 0x12; - case SDLK_2: case SDLK_AT: return 0x13; - case SDLK_3: case SDLK_HASH: return 0x14; - case SDLK_4: case SDLK_DOLLAR: return 0x15; - case SDLK_5: return 0x17; - case SDLK_6: return 0x16; - case SDLK_7: return 0x1a; - case SDLK_8: return 0x1c; - case SDLK_9: return 0x19; - case SDLK_0: return 0x1d; - - case SDLK_BACKQUOTE: case 167: return 0x32; - case SDLK_MINUS: case SDLK_UNDERSCORE: return 0x1b; - case SDLK_EQUALS: case SDLK_PLUS: return 0x18; - case SDLK_LEFTBRACKET: return 0x21; - case SDLK_RIGHTBRACKET: return 0x1e; - case SDLK_BACKSLASH: return 0x2a; - case SDLK_SEMICOLON: case SDLK_COLON: return 0x29; - case SDLK_QUOTE: case SDLK_QUOTEDBL: return 0x27; - case SDLK_COMMA: case SDLK_LESS: return 0x2b; - case SDLK_PERIOD: case SDLK_GREATER: return 0x2f; - case SDLK_SLASH: case SDLK_QUESTION: return 0x2c; - case SDLK_TAB: if (is_hotkey_down(ks)) {if (!key_down) drv->suspend(); return -2;} else return 0x30; case SDLK_RETURN: if (is_hotkey_down(ks)) {if (!key_down) toggle_fullscreen = true; return -2;} else return 0x24; - case SDLK_SPACE: return 0x31; - case SDLK_BACKSPACE: return 0x33; - - case SDLK_DELETE: return 0x75; - case SDLK_INSERT: return 0x72; - case SDLK_HOME: case SDLK_HELP: return 0x73; - case SDLK_END: return 0x77; - case SDLK_PAGEUP: return 0x74; - case SDLK_PAGEDOWN: return 0x79; - - case SDLK_LCTRL: return 0x36; - case SDLK_RCTRL: return 0x36; - case SDLK_LSHIFT: return 0x38; - case SDLK_RSHIFT: return 0x38; -#ifdef __APPLE__ - case SDLK_LALT: return 0x3a; - case SDLK_RALT: return 0x3a; - case SDLK_LGUI: return 0x37; - case SDLK_RGUI: return 0x37; -#else - case SDLK_LALT: return 0x37; - case SDLK_RALT: return 0x37; - case SDLK_LGUI: return 0x3a; - case SDLK_RGUI: return 0x3a; -#endif - case SDLK_MENU: return 0x32; - case SDLK_CAPSLOCK: return 0x39; - case SDLK_NUMLOCKCLEAR: return 0x47; - - case SDLK_UP: return 0x3e; - case SDLK_DOWN: return 0x3d; - case SDLK_LEFT: return 0x3b; - case SDLK_RIGHT: return 0x3c; - case SDLK_ESCAPE: if (is_hotkey_down(ks)) {if (!key_down) { quit_full_screen = true; emerg_quit = true; } return -2;} else return 0x35; - case SDLK_F1: if (is_hotkey_down(ks)) {if (!key_down) SysMountFirstFloppy(); return -2;} else return 0x7a; - case SDLK_F2: return 0x78; - case SDLK_F3: return 0x63; - case SDLK_F4: return 0x76; - case SDLK_F5: return 0x60; - case SDLK_F6: return 0x61; - case SDLK_F7: return 0x62; - case SDLK_F8: return 0x64; - case SDLK_F9: return 0x65; - case SDLK_F10: return 0x6d; - case SDLK_F11: return 0x67; - case SDLK_F12: return 0x6f; - - case SDLK_PRINTSCREEN: return 0x69; - case SDLK_SCROLLLOCK: return 0x6b; - case SDLK_PAUSE: return 0x71; - - case SDLK_KP_0: return 0x52; - case SDLK_KP_1: return 0x53; - case SDLK_KP_2: return 0x54; - case SDLK_KP_3: return 0x55; - case SDLK_KP_4: return 0x56; - case SDLK_KP_5: return 0x57; - case SDLK_KP_6: return 0x58; - case SDLK_KP_7: return 0x59; - case SDLK_KP_8: return 0x5b; - case SDLK_KP_9: return 0x5c; - case SDLK_KP_PERIOD: return 0x41; - case SDLK_KP_PLUS: return 0x45; - case SDLK_KP_MINUS: return 0x4e; - case SDLK_KP_MULTIPLY: return 0x43; - case SDLK_KP_DIVIDE: return 0x4b; - case SDLK_KP_ENTER: return 0x4c; - case SDLK_KP_EQUALS: return 0x51; + default: return usb_to_adb_scancode[ks.scancode]; } - D(bug("Unhandled SDL keysym: %d\n", ks.sym)); - return -1; } static int event2keycode(SDL_KeyboardEvent const &ev, bool key_down) From 3426cb7d4681d4fbedce3599b7ac896b9301b114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Sun, 10 Nov 2019 14:16:33 +0100 Subject: [PATCH 21/22] add all video modes when rootless --- BasiliskII/src/SDL/video_sdl2.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/BasiliskII/src/SDL/video_sdl2.cpp b/BasiliskII/src/SDL/video_sdl2.cpp index a514baec..8dec5feb 100644 --- a/BasiliskII/src/SDL/video_sdl2.cpp +++ b/BasiliskII/src/SDL/video_sdl2.cpp @@ -1484,8 +1484,14 @@ bool VideoInit(bool classic) } #ifdef VIDEO_ROOTLESS } else if (display_type == DISPLAY_ROOTLESS) { - for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++) - add_mode(display_type, default_width, default_height, 0x80, TrivialBytesPerRow(default_width, (video_depth)d), d); + for (int i = 0; video_modes[i].w != 0; i++) { + const int w = video_modes[i].w; + const int h = video_modes[i].h; + if (i > 0 && (w >= default_width || h >= default_height)) + continue; + for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++) + add_mode(display_type, w, h, video_modes[i].resolution_id, TrivialBytesPerRow(w, (video_depth)d), d); + } #endif } From 5e2158f85fad653d4dd2ff4e2a53f06b43a4600a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesu=CC=81s=20A=2E=20A=CC=81lvarez?= Date: Sun, 10 Nov 2019 14:17:02 +0100 Subject: [PATCH 22/22] don't skip frame when changing screen size --- BasiliskII/src/SDL/video_rootless.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/BasiliskII/src/SDL/video_rootless.cpp b/BasiliskII/src/SDL/video_rootless.cpp index f8a10275..6c667ba7 100644 --- a/BasiliskII/src/SDL/video_rootless.cpp +++ b/BasiliskII/src/SDL/video_rootless.cpp @@ -403,17 +403,16 @@ void update_display_mask(SDL_Window *window, int w, int h) { update_sdl_video(NULL, 1, &rect); mask_rects.push_back(rect); memset(display_mask.pixels, 0xff, 2 * display_mask.w * display_mask.h); - return; + } else { + // clear all + memset(display_mask.pixels, 0, display_mask.w * display_mask.h); + + // show non-desktop + uint32 deskPort = ReadMacInt32(0x9E2); + uint32 deskPortVisRgn = ReadMacInt32(ReadMacInt32(deskPort + 0x18)); + MaskRegion(deskPortVisRgn, false); } - // clear all - memset(display_mask.pixels, 0, display_mask.w * display_mask.h); - - // show non-desktop - uint32 deskPort = ReadMacInt32(0x9E2); - uint32 deskPortVisRgn = ReadMacInt32(ReadMacInt32(deskPort + 0x18)); - MaskRegion(deskPortVisRgn, false); - bool has_front_process = false; M68kRegisters r;