Skip to content

m68kemu.library: GadTools gadgets, shared IDCMP ports, real window borders (Blitz programs) - #1904

Closed
terminills wants to merge 102 commits into
aros-development-team:masterfrom
terminills:m68k-13-blitz
Closed

terminills wants to merge 102 commits into
aros-development-team:masterfrom
terminills:m68k-13-blitz

Conversation

@terminills

Copy link
Copy Markdown
Contributor

Depends on #1855-#1859, #1897, #1898, #1899, #1900, #1901, #1902, #1903 (included; review the last 13 commits).

Blitz Basic programs, tested with A_Sweeper 1.05. Most of this comes from bsek's work on top of #1859.

  • icon images go to 68k programs in their own byte order; Image data past the program's memory is not copied
  • console.device RawKeyConvert; PROGDIR: is the program's own directory; IntuitionBase->FirstScreen lists the screens
  • GTMN_TextAttr in LayoutMenusA/LayoutMenuItemsA
  • shared IDCMP ports set by the program (ModifyIDCMP, CloseWindow with a cleared port)
  • IntuiMessages update the window's MouseX/MouseY; MoveWindow/SizeWindow refresh the window box
  • GadTools gadgets are built natively with an m68k mirror for the program; Window->FirstGadget lists them
  • 68k programs are told the window borders they really get (the screen's WBor*, the decoration's sizing gadget); windows sized from the outside still grow by what the decoration adds

QEMU: A_Sweeper 1.05 runs and plays, its grid, status bar and settings fields inside the window; regression unchanged.

…RELOCS)

On a non-68k host LoadSeg() relocates a hunk file to the addresses of
its own segments and nothing can run it there; an emulator copies the
segments into its own memory and needs to relocate them again. Record
every 32-bit relocation the loader applies (hunk, offset, target, kind)
in the seglist's segdata node, in the same allocation, and hand the
table out through a new GetSegListInfo() tag. A failed allocation marks
the table lost rather than handing out a partial one.
A program that opens an optional library (LZX opens arp.library) made
the loader try LIBS68K:name with requesters enabled; with no such assign
dos put up "Please insert volume LIBS68K" and the program waited on it
forever. Turn requesters off for the three probes, as programs do.
…dArgs results

Three things a 68k program needs on a 64-bit host and did not get:

LoadHunks copied the segments dos had relocated to their host addresses
into containment without relocating them again, so every absolute
pointer pointed at host memory; a program without relocations was the
only kind that ran. Apply the list dos now keeps with the seglist
(GSLI_68KRELOCS), the exact inverse of what the loader did.

A native BPTR is a 64-bit pointer and the thunks moved it through 32-bit
registers; with memory above 4 GB a file handle lost its top half and
the first Write() took dos down. Hand the m68k side an index into a
per-context table instead (same native BPTR, same handle), in the
generator's bptr class and the manual dos thunks; Close/UnLock/FreeArgs
release the slot.

ReadArgs() filled the m68k array with native pointers: strings, /N
longs and /M string arrays the program could not reach. Copy them into
one containment block per call and free it in FreeArgs().
…d OpenResource

Each manual table's count was a literal; an added entry fell off the end
and the dispatcher took the generated thunk instead. OpenResource was one
of those generated thunks and returned a native resource base, a 64-bit
pointer the 68k side then called through. A resource the emulator does
not thunk now reads as absent, as a missing library does.
…he native version

A fake base was four bytes; a program reading lib_Version through it
read whatever followed. AROS's own startup compares dos.library's
version with the one the program was built against and exits with
RETURN_FAIL, so every AROS-built 68k command but Echo stopped after a
few instructions. Lay out a full struct Library behind the jump table
and copy the native library's version and revision into it.
…ed libraries

The lists in the fake ExecBase are empty. SysInfo looks expansion.library
up with FindName(&SysBase->LibList, ...) instead of opening it, assumes
the result and calls FindConfigDev() through it, so it jumped through
zero. Answer a lookup in LibList with the thunked base, setting it up on
demand as OpenLibrary() does; devices and resources still read as absent.
What a classic system-friendly program needs beyond library calls, found
by running SysInfo until it stopped asking for things:

- the fake graphics, intuition and dos bases carry their full m68k layout
  synced from the native library; OpenScreen/CloseScreen keep
  IntuitionBase.ActiveScreen/FirstScreen and GfxBase.ActiView pointing at
  the program's screen (SysInfo takes &ActiveScreen->ViewPort unchecked)
- the child process gets NP_Arguments, so ReadArgs on the transparent
  path sees the command line
- Supervisor() returns with the caller's own SR; a user stack exists
- the interrupt mask is lowered after reset; INTB_VERTB servers run as a
  level 3 autovector at 50 Hz from timer.device's E clock through a stub
  in low memory
- CIA-A and CIA-B are modelled from the same clock (ports, timers, TOD):
  SysInfo times its tests with CIA-A's TOD
- vectors 2-47 default to a stub that stops the program with a message;
  a MOVEC on a control register the core lacks (68040 TT/MMU) reads 0
  and is skipped by advancing the frame's PC before it is written
- PrintIText, DrawImage and DrawBorder translate their structures,
  byte-swapping plane words and coordinates; FindDisplayInfo hands out an
  opaque handle and GetDisplayInfoData copies DISP/DIMS/NAME field-wise
- GetVPModeID answers INVALID_ID for an unknown ViewPort; CloseDevice on
  a request the emulator did not create is ignored
- a program's screen opens in the Workbench's own mode and size (the VESA
  driver has one mode) and is painted once, since the driver pushes
  damaged regions only
- diagnostics (per-call trace, exception trail, instruction ring,
  vector-table write trap) stay in the code behind ctx->trace_calls

SysInfo 4.4 (Aminet util/moni) now opens its screen, draws its panel and
waits for input on pc-x86_64 SMP in QEMU.
…t as a word

Classic programs draw their frames and logos straight into sc_BitMap.
The screen shadow had no planes, so those writes went nowhere and the
panel came up as text on grey. Give the shadow real planes of the size
the program asked for and, on every byte or word the CPU writes into
them, recompose the touched pixels from all planes and put them on the
native screen with WriteChunkyPixels(); OS drawing and plane drawing then
compose the way they do on one set of bitplanes. The window RastPort's
rp_BitMap points at the same planes.

LoadRGB4() takes its count in D0.W; an assembler caller leaves the high
word dirty, the thunk read all of it and the palette never loaded.

Diagnostics come on with ENV:M68KEMU_TRACE instead of a rebuild.
…ions

Gadgets: AddGList/AddGadget handed the program's m68k-layout gadget list
straight to intuition. Each gadget is now copied into a native one with
its Image/Border renders, IntuiText and PropInfo; a map lets RefreshGList,
RemoveGList, ModifyProp, On/OffGadget find the copy and makes an
IntuiMessage's IAddress name the program's own gadget. Selected state and
prop pots are copied back after each message. SysInfo's buttons render as
bevels and its gadget-up messages arrive with the right gadget.

Heap: FreeMem() of a pointer the heap never handed out (SysInfo frees two
garbage pointers while tearing down a device request it never opened)
became the head of the free list, so every later allocation came from the
vector table. Frees outside the heap, with a bad header, or of a block
already free are now ignored.

FPU: Moira implements no FPU instructions; they throw a C++ exception that
never unwinds here and the emulator thread hung inside the instruction.
Run the core as a 68LC040, where F-line instructions take the Line-F trap,
and report a 68040 without FPU in AttnFlags.

Diagnostics: M68KEMU_TRACE=msg starts the trace at the first IntuiMessage;
with tracing on, a watchdog process reports the emulated CPU's position
every two seconds.
… ExecBase

Both read 0, and SysInfo divides its speed-test tick count by
VBlankFrequency: pressing SPEED stopped it with a divide by zero. The
emulator's vertical blank runs at 50 Hz; say so.
…y hunk, StackSwap

m68k libraries without a native replacement belong in LIBS68K:; when that
assign is not set the loader uses SYS:Libs68k/. LIBS:m68k/ and LIBS: are
still searched, but only a hunk file is taken from any of them: LIBS: also
holds the native libraries, which were read and rejected one by one.

The heap allocates top down, so a library's later hunks sit below its
first one and the Resident scan upward from the first hunk missed a
RomTag kept in the data hunk (AKCC's akccplus.library). Record the span
each load occupies and scan all of it.

exec StackSwap() exchanges the program's stack pointer with stk_Pointer.

The loader's informational lines move behind M68KEMU_TRACE.
The emulator includes the protos of log.resource, diskfont, commodities,
workbench and other libraries outside the kernel set; in a fresh build
tree it could be compiled before they were generated and failed on
proto/log.h.
…uiet failures

Libraries for 68k programs:
- mathffp, mathtrans, mathieeesingbas/trans, mathieeedoubbas/trans are
  computed natively (FFP converted, doubles in D0/D1), with the condition
  codes the callers branch on (Cmp, Tst) set after the call.
- workbench.library: App* registration succeeds without AppMessages yet,
  OpenWorkbenchObjectA runs natively.
- commodities.library: CxBroker and CreateCxObj translate their m68k
  arguments; the generated thunks passed the program's NewBroker as is
  and the native broker code faulted in strcmp.
- intuition menus: SetMenuStrip/ResetMenuStrip/ClearMenuStrip translate the
  program's Menu/MenuItem strip, ItemAddress walks the program's own strip,
  MENUPICK copies Flags and NextSelect back; CloseWindow drops the strip.
- exec SuperState/UserState (the program already runs in supervisor mode)
  and StackSwap.

68k libraries from LIBS68K: run their init function (as a tail call into
68k code when OpenLibrary returns), apply their InitStruct data, and read
WORD-offset function tables; AKCC's akccplus.library works now.

The emulator's process gets a CLI when started from a Shell, so programs
checking pr_CLI see one.

A failing program is reported in one line to the system log (LogDump),
not as a register and instruction dump painted over the screen by the
debug console; the full dump stays behind M68KEMU_TRACE.
…maphores, window shadow

Native objects the program gets back (VisualInfo, CxObj, BOOPSI objects,
devices' units) are pointers that do not fit in D0: they go out as
handles from the BPTR handle table and are decoded on the way in, for
generated and manual thunks alike.

GadTools menus: CreateMenusA builds the strip natively and hands the
program an m68k mirror, with the UserData slot after each Menu/MenuItem;
LayoutMenus(Items)A lay out the native strip and copy the geometry back;
FreeMenus frees both; SetMenuStrip attaches the native strip of a
GadTools menu instead of translating it again. GT_GetIMsg/GT_ReplyIMsg
go through GetMsg's message translation, so messages are not leaked.

OpenWindowTagList translates every pointer-valued WA_ tag by type
(PubScreen, CustomScreen, Gadgets, Checkmark, AmigaKey, Zoom, titles) and
follows TAG_MORE/TAG_SKIP; WA_PubScreen was passed as an m68k address and
the window never opened. The generic tag-list conversion resolves shadows
and handles first and no longer treats small values or the IDCMP/flags
tags as pointers.

Device I/O: an m68k IORequest gets a native twin (timerequest, IOAudio or
IOStdReq) kept in step around OpenDevice, CloseDevice, DoIO, SendIO,
CheckIO, WaitIO and AbortIO; io_Device is an m68k device base whose
BeginIO/AbortIO and timer.device functions are thunks; GetMsg hands back
the program's own request when a device replies. A reply port the program
built in its own memory gets a native twin on its signal bit. Devices
whose request layout is not translated fail to open instead of receiving
an m68k structure. AbortIO is passed on only for a request in flight.

The rest of the semaphore family matches Init/Obtain/ReleaseSemaphore
(the program is one emulated task): attempts succeed, list calls do
nothing, AddSemaphore/FindSemaphore/RemSemaphore keep a name table.

The Window shadow gains WLayer (and the RastPort's rp_Layer) as a layer
shadow with its RastPort and bounds, the border widths and the GZZ size:
a program locking its window's layer called LockLayer(NULL).

QEMU, Aminet batch: AmigaEyes opens its window, Ameko and 7-Zip get past
their libraries and devices, AKCC and SysInfo unchanged; no 68k program
takes the emulator down.
Programs report their errors through EasyRequest, and the call stopped
them instead. The arguments of the text and gadget formats are one m68k
datastream; it is repacked for the native call, and the IDCMP flags are
copied in and out.

The intuition table also had dead second entries for -432 and -438
(lookup takes the first); removed with their no-op thunks.
Every LockPubScreen built a new Screen shadow and none was ever freed,
so a program that locks the screen repeatedly filled the shadow table.
A structure that already has a shadow of its type now gets that one
back, brought up to date.

A Screen shadow from the field tables had no shadows for its embedded
ViewPort and RastPort and a NULL ViewPort.ColorMap (pointer fields
without a layout are written as NULL): ObtainBestPen() on it faulted in
graphics.library. Both screen paths now register the ViewPort and the
RastPort and give the ColorMap a shadow of the native one.
Insert, AddHead, AddTail, Remove, RemHead, RemTail, Enqueue and FindName
ran the native functions on lists in m68k memory, writing 64-bit
little-endian links into 32-bit big-endian nodes. They now link m68k
lists in m68k layout; a list that is a shadow of a native one still goes
to the native function. The choice follows the list, since a program's
nodes may be shadows themselves.
OpenLibrary of a .class, .gadget or .image opens the native class
library behind an m68k base: GetClass, the label node functions of
chooser, clicktab, radiobutton, speedbar and listbrowser, and
RethinkLayout/PAGE_GetClass of layout.gadget.

NewObjectA, DisposeObject, SetAttrsA, GetAttr, SetGadgetAttrsA and
DoGadgetMethodA work on native objects. The program gets an m68k
stand-in for each: an _Object header whose class is an m68k IClass,
and a Gadget-sized body kept in step with the native gadget. The
class's dispatcher hook points at a vector of a pseudo library, so
amiga.lib DoMethod() runs the method on the native object: OM_SET,
OM_GET, OM_DISPOSE and the window.class methods (WM_OPEN returns the
window's shadow, WM_HANDLEINPUT writes the code back).

Tags whose data is a structure in the program's layout are translated:
WINDOW_NewMenu, LISTBROWSER_ColumnInfo, GA_TextAttr, label string
arrays, and label lists - the program links the m68k stand-ins of the
nodes into its own list, and a native copy is built when the list is
passed. ~0 stays ~0. Read-back values that point at native data
(STRINGA_TextVal, SPACE_AreaBox) are copied into memory of the object.
DrawImage draws a BOOPSI image natively.

The shadow table grows to 1024 entries and the library table to 64.

QEMU: the ClassAct 2 68k example binaries (string, fuelgauge, glyph,
page, clicktab, speedbar, SpeedTest) open their windows on the native
classes; AmiLines opens its board.
The m68k MsgPort standing in for a window's UserPort was allocated and
left unfilled. A program that waits with Wait(1 << UserPort->mp_SigBit)
instead of WaitPort() waited on whatever bit the memory held and never
woke. The shadow now has the native port's mp_SigBit and mp_Flags, its
node type and an empty message list.
InitArea and InitTmpRas ran the native functions on the program's m68k
structures, writing native layouts larger than the m68k ones into its
memory, and the native RastPort never saw them. Both now set up native
twins of the program's structures; AreaMove, AreaDraw, AreaEnd,
AreaEllipse and Flood put the twins named by the program's RastPort on
the native RastPort before drawing.

QEMU: AmiLines draws its balls.
The generated Screen table leaves out everything before the ViewPort
but the pointers: LeftEdge, TopEdge, Width, Height, Flags, BarHeight,
the menu and window border sizes, and Font was written as NULL. A
program sizing its window from WBorTop and the screen font (AmigaEyes)
read whatever the shadow's memory held. The screen extras now fill
them, with a TextAttr shadow for the font, and new shadows start
zeroed instead of with stale heap contents.
…WindowTagList

FindTask built a new Process-sized shadow on every call, and programs
call FindTask(NULL) in their loops: AmigaEyes filled the shadow table
with them. A task's existing shadow is now brought up to date and
returned.

OpenWindowTagList ignored a NewWindow passed with the tags. Its fields
are now applied, with the tags taking precedence as on AmigaOS; the
NewWindow translation is shared with OpenWindow. OpenWindow no longer
changes the window's IDCMP when calls are traced, and a traced
OpenWindowTagList lists its tags and the resulting borders. The table
full report gives the full shadow types.
68k programs size their windows from the border widths of AmigaOS 3,
and some count on them without reading them: AmigaEyes adds no bottom
border at all, which costs 2 pixels there and 10 with the AROS
decoration, cutting its eyes in half.

Screens now show the program the classic hires borders (WBorTop 2,
WBorLeft/Right 4, WBorBottom 2), and a window the program sizes from
the outside (WA_Width/WA_Height or a NewWindow, not borderless) grows
by what the screen's decoration adds to them. The window keeps its
real Border* fields, so drawing lands inside. With
M68KEMU_CLASSICBORDERS set to 0 the real borders are shown and
windows open as asked.

QEMU, AmigaEyes: with the decoration it now looks as it does without
one; without the decoration nothing changes.
OpenFont took its TextAttr from A1 instead of A0 and always failed, and
returned the native font, which the program cannot read tf_YSize or
tf_Baseline from; it now returns a TextFont shadow. diskfont.library
had no OpenDiskFont; it shares the TextAttr translation.

The containment heap ignored MEMF_CLEAR, so a block that had been
freed came back with its old contents; AllocVec dropped its
requirements and memory pools had none. Allocations now clear when
asked, AllocVec passes its flags, and CreatePool keeps the pool's flags
for AllocPooled (DeletePool frees the header).

GetScreenData copied the native Screen into the program's m68k Screen
buffer; it now copies the screen's shadow, at most the size asked for.

QEMU: Wordle gets past its fonts and opens its screen (it still stops
later, in its own cleanup); SysInfo, AMines, AKCC, AmiLines, AmigaEyes
and the ClassAct 68k examples unchanged.
Each segment was copied without the size and next-segment BPTR that
LoadSeg() puts before it. A program that walks its own seglist to jump
into a later hunk (AmigaTration's start-up) read the heap's bookkeeping
there and jumped to 08000004. Segments are now copied as LoadSeg() lays
them out, with the links pointing at the copies.
BltBitMap handed m68k struct BitMaps to graphics.library, which read
their plane pointers as native ones and faulted. Between two bitmaps in
the program's memory (its own images, the planes behind its screen) the
blit is now done there, plane by plane with the minterm and mask; with a
native bitmap on one side the m68k one is passed as a planar BitMap over
its planes. A blit into the planes behind the program's screen is shown
on the screen.

QEMU: AmigaTration runs and shows its blitted title, board and panel.
The program's Task shadow had tc_SPLower and tc_SPUpper as NULL (pointer
fields without a layout). Startup code that moves to a bigger stack
copies from tc_SPReg up to tc_SPUpper: 7-Zip's copied through all of
memory for billions of instructions. The program's own task now shows
the emulated stack (lower, upper, register) wherever its shadow is
made or refreshed.
Tag data the native ReAction classes take in the program's layout is now
translated: a plain struct Image given as LABEL_Image, GA_Image,
GA_SelectRender, GA_LabelImage or a node image (SBNA_, LBNCA_, CNA_,
TNA_Image) becomes a native copy kept for the run; IA_Font is a TextAttr
like GA_TextAttr; LABEL_Mapping is a UWORD pen array. RADIOBUTTON_Labels
and SPEEDBAR_Buttons are node lists like the other label lists, and
RADIOBUTTON_LabelArray is the string array.

QEMU: ClassAct 2's 68k ClassActDemo runs through all its pages (logo,
credits, buttons, GadTools replacements, new gadgets, listbrowser, ASL
getters) on the native classes.
When calls are traced, NewObject logs its class, tags and result,
WM_OPEN lists the screen's windows and the window's gadgets with their
hit test, and generated thunks show D0.
AROS reads Image plane data as big-endian words on every port. The
copy of a 68k struct Image converted each word to host order, so on
x86 every plain image a 68k program handed to native code was drawn
with the two bytes of each word swapped: pixels 0-7 and 8-15 traded
places, and images wider than 16 pixels lost the pixels pushed past
their edge. The ClassAct demo's speedbar icons in its ListBrowser
showed this.
intuition NextObject walks the program's own object lists in its memory
and returns the object after its _Object header; FindClass returns the
m68k IClass of the class found.
ExAll read its arguments from the wrong registers. It now takes the
program's ExAllControl (16 bytes in its memory, from AllocDosObject, with
a native one behind it) and fills the program's buffer with ExAllData in
68k layout, over as many calls as the directory needs; ExAllEnd ends a
scan through the same control.

Examine and ExNext keep a native FileInfoBlock behind the program's,
since ExNext's place in fib_DiskKey does not fit in 32 bits. A FIB from
AllocDosObject has its own; others share a small table.

Checked with hand-assembled 68k tests (ExAll over several calls;
Examine/ExNext).
DoPkt read its port from A1 and passed packet arguments unchanged. It
now translates the common actions (DISK_INFO, INFO, LOCATE_OBJECT,
FREE_LOCK, COPY_DIR, PARENT, SAME_LOCK, EXAMINE_OBJECT/NEXT,
IS_FILESYSTEM, CURRENT_VOLUME), those with a dos call of their own going
through it.

GetDeviceProc gives a DevProc in 68k layout whose dvp_Port is a port the
program can pass on, and FreeDeviceProc frees it.
The program's TextExtent was filled in native order, so text was laid
out with byte-swapped heights. TextExtent and TextFit now write it (and
read TextFit's constraining extent) in 68k order.
CreateNewProc is dos -498; the table had it at -492, which is Cli().
With a 68k NP_Entry it now starts a native process that runs the entry
on a CPU of its own over the program's memory, followed by NP_ExitCode
if given. Cli() returns the program's CLI.

The program's state is shared, so a CPU runs 68k code only while it
holds the program's lock (a SignalSemaphore in the context). It lets go
in Wait, WaitPort and Delay, and every 64K instructions when another
task is waiting, unless the program has called Forbid(). The program
waits for its processes to end before its memory goes.

FindTask(NULL) keeps the program's Process for its main task only; a
process of the program gets its own.
PutMsg/GetMsg/ReplyMsg/WaitPort handle messages the program makes: on a
port in its memory they are queued as exec queues them and the port's
task is signalled; to a native port (CreateMsgPort, pr_MsgPort) they
travel in a native carrier, and GetMsg gives back the program's own
message. A process's pr_MsgPort is a port the program can use.

Directory Opus 5.91 does this for every lister and button bank.

Checked with hand-assembled 68k tests (a child process and messages both
ways through a native port and a port in the program's memory) and the
full regression. Directory Opus 5.91 now opens a RAM Disk lister that
reads the volume (free space, directory count) and its button bank with
labels.
exec Disable()/Enable() no longer turn off native interrupts: the
program ran 68k code with them off and the machine stopped scheduling.
They now hold the program's lock like Forbid() and hold back its
vertical blank.
dos Exit() ends the calling task of the program (its CPU stops) instead
of ending the emulator's process inside the call, with the program's
lock held.
CreateNewProc with NP_Seglist: a 68k program's seglist is copied into the
program's memory and runs on a CPU of its own; a native program's
(Directory Opus starts the WBStartup programs) is started natively. Run
as 68k code, a native program corrupted the system.

When calls are traced, LoadSeg logs its name and a CreateNewProc that
starts nothing logs its tags.
A 68k input handler (IND_ADDHANDLER) is accepted and not installed,
since input.device would call 68k code as native code; IND_WRITEEVENT
events are made native.
DoIO and WaitIO let the program's other tasks run while they wait.
The manual graphics table had SetABPenDrMd at -864 (GetBPen) and
ScrollRaster at -318 (ReadPixel). GetBPen and ReadPixel ran the wrong
function with whatever was in the registers, and SetABPenDrMd and
ScrollRaster themselves were unsupported. Directory Opus 5 sets its
lister pens with SetABPenDrMd: its file list was drawn in pen 0 on
pen 0. Every manual table was checked against the generated one; these
were the only two.
The nesting was counted for the program as a whole. A task that waited
inside Forbid() (Wait, WaitPort, Delay, DoIO) left the count set for the
task that ran next, which then never let the others run, and its
Permit() could end the first task's Forbid(). As exec does, a task that
lets go of the program's lock takes its nesting with it and has it back
when it holds the lock again.
A Workbench replacement (Directory Opus 5 runs the WBStartup drawer)
starts a program with CreateNewProc(NP_Seglist) and sends its startup
message to the new process's pr_MsgPort. For a native program the
message is now a native struct WBStartup, its segment, locks and names
translated, replying to the native twin of the program's reply port; the
program gets its own message back with GetMsg(). The native program read
the 68k layout before, and UpdateNotifier faulted on it.
Native icon ImageData is already big-endian bitplane bytes, both for
classic icons and for the planar fallback of PNG icons. put_image read
it as host words and wrote each word out big-endian again, which on a
little-endian host swaps every pair of bytes, so neighbouring 8-pixel
columns of each icon changed places. Copy the planes as they are; only
the Image fields need converting.
image_from_m68k() bounded the plane count but not where ImageData points,
so an Image with a stray data pointer near the top of the 68k address
space read past the end of the emulated memory. Leave such images empty.

Found by bsek testing A_Sweeper 1.05.
Programs that open console.device for RawKeyConvert() (Blitz Basic's
keyboard input does) called a function the device base did not have.
Give console.device its own vector table with RawKeyConvert, converting
the m68k InputEvent and using the default keymap, since an m68k KeyMap
has a different layout.

From bsek's work on A_Sweeper 1.05.
A program started through RunHunk got the caller's PROGDIR:, so data
files next to the program were not found. Pass the parent of the loaded
file as NP_HomeDir, or set it with SetProgramDir() for the duration of
a direct run.

From bsek's work on A_Sweeper 1.05.
Blitz Basic looks for the Workbench screen by walking FirstScreen and
found an empty list. When the intuition.library base is set up, link
Screen shadows of the native screens under the IBase lock, and fill in
ActiveScreen.

From bsek's work on A_Sweeper 1.05.
The generic tag copy passed the m68k TextAttr pointer to GadTools as it
was. Convert the TextAttr natively, or drop the tag if it cannot be read.

From bsek's work on A_Sweeper 1.05.
Programs share one IDCMP port among their windows: they open a window
without IDCMP flags, put their own port (or another window's) into
Window->UserPort and call ModifyIDCMP(), and clear UserPort again before
CloseWindow(). Hand the port the program set to the native window in
ModifyIDCMP(), keep the window's UserPort shadow in step with the native
one, and leave a cleared shared port alone in CloseWindow().

From bsek's work on A_Sweeper 1.05.
Blitz Basic's WMouseX/WMouseY read the pointer position from the Window
structure, which stayed at its value from when the window opened.

From bsek's work on A_Sweeper 1.05.
Intuition moves and sizes a window asynchronously, and programs read
LeftEdge/Width back from the window right after the call. Wait briefly
for the native box to change, then copy it into the window shadow.

From bsek's work on A_Sweeper 1.05.
CreateContext() and CreateGadgetA() had no thunks, and the generated
FreeGadgets() and GT_Set/GetGadgetAttrsA() thunks took m68k Gadgets for
native ones. Let GadTools build the gadgets natively and give the
program an m68k mirror of each (box, flags, ID, UserData, NextGadget),
kept in the gadget map so AddGList(), GT_SetGadgetAttrsA() and IDCMP
messages translate between the two. GENERIC_KIND gadgets are finished by
the program in the mirror, so their imagery and flags are carried over
before the list goes into a window. GT_GetGadgetAttrsA() fills the
program's ULONGs, cycle and mx labels are rebuilt natively, and a
VisualInfo is handed out as a handle since its address can fall inside
the program's memory.

The generated GT_FilterIMsg() thunk re-synced the message shadow from the
native message, losing the IAddress and IDCMPWindow GetMsg() had
translated; keep the program's message when GadTools returns it unchanged.

From bsek's work on A_Sweeper 1.05.
Programs walk Window->FirstGadget themselves. Link the program's gadgets
there in native order after AddGList(), AddGadget(), RemoveGList() and
RemoveGadget(); system gadgets have no m68k counterpart and are left out.

From bsek's work on A_Sweeper 1.05.
The Screen shadow showed classic AmigaOS borders while a window got the
decoration's. Programs that place gadgets from the screen's WBor* values
but draw from Window->BorderTop then disagreed with themselves: in
A_Sweeper the status bar covered the last row of the grid and the first
settings field sat under the title bar.

The Screen now shows the decoration's own borders. A window sized from
the outside still grows by what those take beyond the classic ones; with
a sizing gadget, the decoration is asked for its size as Intuition does
it. The program keeps seeing the size it asked for, so a SizeWindow() it
computes from that keeps the extra room.
@terminills

Copy link
Copy Markdown
Contributor Author

Squashed into one pull request as asked: #1905.

@terminills terminills closed this Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant