diff options
Diffstat (limited to 'emu/MacOSX')
| -rw-r--r-- | emu/MacOSX/NOTE | 4 | ||||
| -rw-r--r-- | emu/MacOSX/NOTICE | 3 | ||||
| -rw-r--r-- | emu/MacOSX/asm-386.s | 28 | ||||
| -rw-r--r-- | emu/MacOSX/asm-power.s | 36 | ||||
| -rw-r--r-- | emu/MacOSX/cmd.c | 214 | ||||
| -rw-r--r-- | emu/MacOSX/deveia.c | 154 | ||||
| -rw-r--r-- | emu/MacOSX/devfs.c | 1 | ||||
| -rw-r--r-- | emu/MacOSX/emu | 108 | ||||
| -rw-r--r-- | emu/MacOSX/emu-g | 96 | ||||
| -rw-r--r-- | emu/MacOSX/ipif.c | 1 | ||||
| -rw-r--r-- | emu/MacOSX/keycodes.h | 189 | ||||
| -rw-r--r-- | emu/MacOSX/mkfile | 63 | ||||
| -rw-r--r-- | emu/MacOSX/mkfile-g | 62 | ||||
| -rw-r--r-- | emu/MacOSX/mkfile-x11 | 64 | ||||
| -rw-r--r-- | emu/MacOSX/os.c | 647 | ||||
| -rw-r--r-- | emu/MacOSX/win.c | 755 |
16 files changed, 2425 insertions, 0 deletions
diff --git a/emu/MacOSX/NOTE b/emu/MacOSX/NOTE new file mode 100644 index 00000000..b9f8748f --- /dev/null +++ b/emu/MacOSX/NOTE @@ -0,0 +1,4 @@ +- still interp mode only, jit not complete +- mkfile uses Carbon only; mkfile-x11 uses X11R6 from Apple +- both powerpc and x86 versions compiled from this source +- mkfile-g doesn't include graphics (uses emu-g not emu as configuration) diff --git a/emu/MacOSX/NOTICE b/emu/MacOSX/NOTICE new file mode 100644 index 00000000..a14c52c9 --- /dev/null +++ b/emu/MacOSX/NOTICE @@ -0,0 +1,3 @@ +MacOSX port Copyright © 2001-2003 Corpus Callosum Corporation, +with portions Copyright © 2001-2003 Geoff Collyer +MacOSX-x86 Copyright © 2006 Corpus Callosum Corporation diff --git a/emu/MacOSX/asm-386.s b/emu/MacOSX/asm-386.s new file mode 100644 index 00000000..fc903bcb --- /dev/null +++ b/emu/MacOSX/asm-386.s @@ -0,0 +1,28 @@ +/* + * these are the same as on the PC (eg, Linux) +*/ + + .globl _FPsave +_FPsave: + pushl %ebp + movl %esp, %ebp + movl 8(%ebp), %eax + fstenv (%eax) + popl %ebp + ret + + .globl _FPrestore +_FPrestore: + pushl %ebp + movl %esp, %ebp + movl 8(%ebp), %eax + fldenv (%eax) + popl %ebp + ret + + .globl __tas +__tas: + movl $1, %eax + movl 4(%esp), %ecx + xchgl %eax, 0(%ecx) + ret diff --git a/emu/MacOSX/asm-power.s b/emu/MacOSX/asm-power.s new file mode 100644 index 00000000..d7db8188 --- /dev/null +++ b/emu/MacOSX/asm-power.s @@ -0,0 +1,36 @@ +/* + * File: asm-power.s + * + * Copyright (c) 2003, Corpus Callosum Corporation. All rights reserved. + */ + +#include <architecture/ppc/asm_help.h> + +.text + +LEAF(_FPsave) + mffs f0 + stfd f0,0(r3) + blr +END(_FPsave) + +LEAF(_FPrestore) + lfd f0,0(r3) + mtfsf 0xff,f0 + blr +END(_FPrestore) + +LEAF(__tas) + sync + mr r4,r3 + addi r5,0,0x1 +1: + lwarx r3,0,r4 + cmpwi r3,0x0 + bne- 2f + stwcx. r5,0,r4 + bne- 1b /* Lost reservation, try again */ +2: + sync + blr +END(__tas) diff --git a/emu/MacOSX/cmd.c b/emu/MacOSX/cmd.c new file mode 100644 index 00000000..58f6dba7 --- /dev/null +++ b/emu/MacOSX/cmd.c @@ -0,0 +1,214 @@ +#include <sys/types.h> +#include <signal.h> +#include <pwd.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <fcntl.h> + +#include "dat.h" +#include "fns.h" +#include "error.h" + +enum +{ + Debug = 0 +}; + +/* + * os-specific devcmd support. + * this version should be reasonably portable across Unix systems. + */ +typedef struct Targ Targ; +struct Targ +{ + int fd[3]; /* fd[0] is standard input, fd[1] is standard output, fd[2] is standard error */ + char** args; + char* dir; + int pid; + int wfd; /* child writes errors that occur after the fork or on exec */ + int uid; + int gid; +}; + +extern int gidnobody; +extern int uidnobody; + +static int +childproc(Targ *t) +{ + int i, nfd; + + if(Debug) + print("devcmd: '%s'", t->args[0]); + + nfd = getdtablesize(); + for(i = 0; i < nfd; i++) + if(i != t->fd[0] && i != t->fd[1] && i != t->fd[2] && i != t->wfd) + close(i); + + dup2(t->fd[0], 0); + dup2(t->fd[1], 1); + dup2(t->fd[2], 2); + close(t->fd[0]); + close(t->fd[1]); + close(t->fd[2]); + + /* should have an auth file to do host-specific authorisation? */ + if(t->gid != -1){ + if(setgid(t->gid) < 0 && getegid() == 0){ + fprint(t->wfd, "can't set gid %d: %s", t->gid, strerror(errno)); + _exit(1); + } + } + + if(t->uid != -1){ + if(setuid(t->uid) < 0 && geteuid() == 0){ + fprint(t->wfd, "can't set uid %d: %s", t->uid, strerror(errno)); + _exit(1); + } + } + + if(t->dir != nil && chdir(t->dir) < 0){ + fprint(t->wfd, "can't chdir to %s: %s", t->dir, strerror(errno)); + _exit(1); + } + + signal(SIGPIPE, SIG_DFL); + + execvp(t->args[0], t->args); + if(Debug) + print("execvp: %s\n",strerror(errno)); + fprint(t->wfd, "exec failed: %s", strerror(errno)); + + _exit(1); +} + +void* +oscmd(char **args, int nice, char *dir, int *fd) +{ + Targ *t; + int r, fd0[2], fd1[2], fd2[2], wfd[2], n, pid; + + t = mallocz(sizeof(*t), 1); + if(t == nil) + return nil; + + fd0[0] = fd0[1] = -1; + fd1[0] = fd1[1] = -1; + fd2[0] = fd2[1] = -1; + wfd[0] = wfd[1] = -1; + if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(wfd) < 0) + goto Error; + if(fcntl(wfd[1], F_SETFD, FD_CLOEXEC) < 0) /* close on exec to give end of file on success */ + goto Error; + + t->fd[0] = fd0[0]; + t->fd[1] = fd1[1]; + t->fd[2] = fd2[1]; + t->wfd = wfd[1]; + t->args = args; + t->dir = dir; + t->gid = up->env->gid; + if(t->gid == -1) + t->gid = gidnobody; + t->uid = up->env->uid; + if(t->uid == -1) + t->uid = uidnobody; + + signal(SIGCHLD, SIG_DFL); + switch(pid = fork()) { + case -1: + goto Error; + case 0: + setpgid(0, getpid()); + if(nice) + oslopri(); + childproc(t); + _exit(1); + default: + t->pid = pid; + if(Debug) + print("cmd pid %d\n", t->pid); + break; + } + + close(fd0[0]); + close(fd1[1]); + close(fd2[1]); + close(wfd[1]); + + n = read(wfd[0], up->genbuf, sizeof(up->genbuf)-1); + close(wfd[0]); + if(n > 0){ + close(fd0[1]); + close(fd1[0]); + close(fd2[0]); + free(t); + up->genbuf[n] = 0; + if(Debug) + print("oscmd: bad exec: %q\n", up->genbuf); + error(up->genbuf); + return nil; + } + + fd[0] = fd0[1]; + fd[1] = fd1[0]; + fd[2] = fd2[0]; + return t; + +Error: + r = errno; + if(Debug) + print("oscmd: %q\n",strerror(r)); + close(fd0[0]); + close(fd0[1]); + close(fd1[0]); + close(fd1[1]); + close(fd2[0]); + close(fd2[1]); + close(wfd[0]); + close(wfd[1]); + error(strerror(r)); + return nil; +} + +int +oscmdkill(void *a) +{ + Targ *t = a; + + if(Debug) + print("kill: %d\n", t->pid); + return kill(-t->pid, SIGTERM); +} + +int +oscmdwait(void *a, char *buf, int n) +{ + Targ *t = a; + int s; + + if(waitpid(t->pid, &s, 0) == -1){ + if(Debug) + print("wait error: %d [in %d] %q\n", t->pid, getpid(), strerror(errno)); + return -1; + } + if(WIFEXITED(s)){ + if(WEXITSTATUS(s) == 0) + return snprint(buf, n, "%d 0 0 0 ''", t->pid); + return snprint(buf, n, "%d 0 0 0 'exit: %d'", t->pid, WEXITSTATUS(s)); + } + if(WIFSIGNALED(s)){ + if(WTERMSIG(s) == SIGTERM || WTERMSIG(s) == SIGKILL) + return snprint(buf, n, "%d 0 0 0 killed", t->pid); + return snprint(buf, n, "%d 0 0 0 'signal: %d'", t->pid, WTERMSIG(s)); + } + return snprint(buf, n, "%d 0 0 0 'odd status: 0x%x'", t->pid, s); +} + +void +oscmdfree(void *a) +{ + free(a); +} diff --git a/emu/MacOSX/deveia.c b/emu/MacOSX/deveia.c new file mode 100644 index 00000000..bb7a01c6 --- /dev/null +++ b/emu/MacOSX/deveia.c @@ -0,0 +1,154 @@ +/* + * Darwin serial port definitions, uses IOKit to build sysdev + * Loosely based on FreeBSD/deveia.c + * Copyright © 1998, 1999 Lucent Technologies Inc. All rights reserved. + * Revisions Copyright © 1999, 2000 Vita Nuova Limited. All rights reserved. + * Revisions Copyright © 2003 Corpus Callosum Corporation. All rights reserved. +*/ + +#include <termios.h> +#include <sys/param.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> + +#include <mach/mach.h> + +#include <CoreFoundation/CFNumber.h> + +#include <IOKit/IOKitLib.h> +#include <IOKit/IOCFPlugIn.h> +#include <IOKit/usb/IOUSBLib.h> +#include <IOKit/serial/IOSerialKeys.h> +#include <IOKit/IOBSD.h> + +#define B14400 14400 +#define B28800 28800 +#define B57600 57600 +#define B76800 76800 +#define B115200 115200 +#define B230400 230400 + +extern int vflag; + +#define MAXDEV 8 +static char *sysdev[MAXDEV]; + +#include <sys/ioctl.h> +#include <sys/ttycom.h> + +static void _buildsysdev(void); +#define buildsysdev() _buildsysdev() /* for devfs-posix.c */ + +static void +_buildsysdev(void) +{ + kern_return_t kernResult; + mach_port_t masterPort; + CFMutableDictionaryRef classesToMatch; + io_iterator_t serialPortIterator; + io_object_t serialDevice; + CFMutableArrayRef array; + CFIndex idx; + + kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort); + if (KERN_SUCCESS != kernResult) + { + printf("IOMasterPort returned %d\n", kernResult); + } else { + classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); + if (classesToMatch == NULL) + { + printf("IOServiceMatching returned a NULL dictionary.\n"); + } else { + CFDictionarySetValue(classesToMatch, + CFSTR(kIOSerialBSDTypeKey), + CFSTR(kIOSerialBSDAllTypes)); + } + + kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch, &serialPortIterator); + if (KERN_SUCCESS != kernResult) + { + printf("IOServiceGetMatchingServices returned %d\n", kernResult); + } else { + array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + + while ((serialDevice = IOIteratorNext(serialPortIterator))) { + CFTypeRef bsdPathAsCFString; + bsdPathAsCFString = IORegistryEntryCreateCFProperty(serialDevice, + CFSTR(kIOCalloutDeviceKey), + kCFAllocatorDefault, + 0); + if (bsdPathAsCFString) { + CFArrayAppendValue(array, bsdPathAsCFString); + } + + (void) IOObjectRelease(serialDevice); + } + + idx = CFArrayGetCount(array); + if (idx > 0) { + Boolean result; + char bsdPath[MAXPATHLEN]; + char *tmpsysdev[idx+1]; + CFIndex i; + + for (i=0; i<idx; i++) { + result = CFStringGetCString(CFArrayGetValueAtIndex(array, i), + bsdPath, + sizeof(bsdPath), + kCFStringEncodingASCII); + if (result) { + int len = strlen(bsdPath); + tmpsysdev[i] = (char *)malloc((len+1)*sizeof(char)); + strcpy(tmpsysdev[i], bsdPath); + } + } + tmpsysdev[idx] = NULL; + for (i=0; i < idx; i++) { + sysdev[i] = tmpsysdev[i]; + if (vflag) + printf("BSD path: '%s'\n", sysdev[i]); + } + } + + CFRelease(array); + } + } + + if (serialPortIterator) + IOObjectRelease(serialPortIterator); + if (masterPort) + mach_port_deallocate(mach_task_self(), masterPort); + + return; +} + +#undef nil + +#include "deveia-posix.c" +#include "deveia-bsd.c" + +static struct tcdef_t bps[] = { + {0, B0}, + {50, B50}, + {75, B75}, + {110, B110}, + {134, B134}, + {150, B150}, + {200, B200}, + {300, B300}, + {600, B600}, + {1200, B1200}, + {1800, B1800}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, + {19200, B19200}, + {38400, B38400}, + {57600, B57600}, + {76800, B76800}, + {115200, B115200}, + {230400, B230400}, + {0, -1} +}; diff --git a/emu/MacOSX/devfs.c b/emu/MacOSX/devfs.c new file mode 100644 index 00000000..9017c3fc --- /dev/null +++ b/emu/MacOSX/devfs.c @@ -0,0 +1 @@ +#include "devfs-posix.c" diff --git a/emu/MacOSX/emu b/emu/MacOSX/emu new file mode 100644 index 00000000..91efe264 --- /dev/null +++ b/emu/MacOSX/emu @@ -0,0 +1,108 @@ +dev + root + cons + env + mnt + pipe + prog + prof + srv + dup + ssl + cap + fs + cmd cmd + indir + + draw win + pointer + snarf + + ip ipif ipaux + eia +# audio audio + mem + +lib + interp + tk + freetype + math + draw + + memlayer + memdraw + keyring + sec + mp + + 9 + +link + +mod + sys + draw + + tk + math + srv srv + keyring + loader + freetype + +port + alloc + cache + chan + dev + dial + dis + discall + env + error + errstr + exception + exportfs + inferno + latin1 + main + parse + pgrp + print + proc + qio + random + sysfile + uqid + +code + int dontcompile = 1; + int macjit = 1; + +init + emuinit + +root + /dev / + /fd / + /prog / + /net / + /net.alt / + /chan / + /nvfs / + /env / +# /chan +# /dev +# /dis +# /env +# /n +# /net +# /nvfs / +# /prog +# /icons +# /osinit.dis +# /dis/emuinit.dis +# /dis/lib/auth.dis +# /dis/lib/ssl.dis +# /n/local / diff --git a/emu/MacOSX/emu-g b/emu/MacOSX/emu-g new file mode 100644 index 00000000..380ece95 --- /dev/null +++ b/emu/MacOSX/emu-g @@ -0,0 +1,96 @@ +dev + root + cons + env + mnt + pipe + prog + prof + srv + dup + ssl + cap + fs + cmd cmd + indir + + ip ipif ipaux + eia +# audio audio + mem + +lib + interp + math + keyring + sec + mp + + 9 + +link + +mod + sys + math + srv srv + keyring + loader + +port + alloc + cache + chan + dev + dial + dis + discall + env + error + errstr + exception + exportfs + inferno + latin1 + main + parse + pgrp + print + proc + qio + random + sysfile + uqid + +code + int dontcompile = 1; + int macjit = 1; + void setpointer(int x, int y){USED(x); USED(y);} + ulong strtochan(char *s){USED(s); return ~0;} + +init + emuinit + +root + /dev / + /fd / + /prog / + /net / + /net.alt / + /chan / + /nvfs / + /env / +# /chan +# /dev +# /dis +# /env +# /n +# /net +# /nvfs / +# /prog +# /icons +# /osinit.dis +# /dis/emuinit.dis +# /dis/lib/auth.dis +# /dis/lib/ssl.dis +# /n/local / diff --git a/emu/MacOSX/ipif.c b/emu/MacOSX/ipif.c new file mode 100644 index 00000000..060c4087 --- /dev/null +++ b/emu/MacOSX/ipif.c @@ -0,0 +1 @@ +#include "../FreeBSD/ipif.c" diff --git a/emu/MacOSX/keycodes.h b/emu/MacOSX/keycodes.h new file mode 100644 index 00000000..52328ace --- /dev/null +++ b/emu/MacOSX/keycodes.h @@ -0,0 +1,189 @@ +/* These are the Macintosh key scancode constants -- from Inside Macintosh */ +#define QZ_ESCAPE 0x35 +#define QZ_F1 0x7A +#define QZ_F2 0x78 +#define QZ_F3 0x63 +#define QZ_F4 0x76 +#define QZ_F5 0x60 +#define QZ_F6 0x61 +#define QZ_F7 0x62 +#define QZ_F8 0x64 +#define QZ_F9 0x65 +#define QZ_F10 0x6D +#define QZ_F11 0x67 +#define QZ_F12 0x6F +#define QZ_PRINT 0x69 +#define QZ_SCROLLOCK 0x6B +#define QZ_PAUSE 0x71 +#define QZ_POWER 0x7F +#define QZ_BACKQUOTE 0x32 +#define QZ_1 0x12 +#define QZ_2 0x13 +#define QZ_3 0x14 +#define QZ_4 0x15 +#define QZ_5 0x17 +#define QZ_6 0x16 +#define QZ_7 0x1A +#define QZ_8 0x1C +#define QZ_9 0x19 +#define QZ_0 0x1D +#define QZ_MINUS 0x1B +#define QZ_EQUALS 0x18 +#define QZ_BACKSPACE 0x33 +#define QZ_INSERT 0x72 +#define QZ_HOME 0x73 +#define QZ_PAGEUP 0x74 +#define QZ_NUMLOCK 0x47 +#define QZ_KP_EQUALS 0x51 +#define QZ_KP_DIVIDE 0x4B +#define QZ_KP_MULTIPLY 0x43 +#define QZ_TAB 0x30 +#define QZ_q 0x0C +#define QZ_w 0x0D +#define QZ_e 0x0E +#define QZ_r 0x0F +#define QZ_t 0x11 +#define QZ_y 0x10 +#define QZ_u 0x20 +#define QZ_i 0x22 +#define QZ_o 0x1F +#define QZ_p 0x23 +#define QZ_LEFTBRACKET 0x21 +#define QZ_RIGHTBRACKET 0x1E +#define QZ_BACKSLASH 0x2A +#define QZ_DELETE 0x75 +#define QZ_END 0x77 +#define QZ_PAGEDOWN 0x79 +#define QZ_KP7 0x59 +#define QZ_KP8 0x5B +#define QZ_KP9 0x5C +#define QZ_KP_MINUS 0x4E +#define QZ_CAPSLOCK 0x39 +#define QZ_a 0x00 +#define QZ_s 0x01 +#define QZ_d 0x02 +#define QZ_f 0x03 +#define QZ_g 0x05 +#define QZ_h 0x04 +#define QZ_j 0x26 +#define QZ_k 0x28 +#define QZ_l 0x25 +#define QZ_SEMICOLON 0x29 +#define QZ_QUOTE 0x27 +#define QZ_RETURN 0x24 +#define QZ_KP4 0x56 +#define QZ_KP5 0x57 +#define QZ_KP6 0x58 +#define QZ_KP_PLUS 0x45 +#define QZ_LSHIFT 0x38 +#define QZ_z 0x06 +#define QZ_x 0x07 +#define QZ_c 0x08 +#define QZ_v 0x09 +#define QZ_b 0x0B +#define QZ_n 0x2D +#define QZ_m 0x2E +#define QZ_COMMA 0x2B +#define QZ_PERIOD 0x2F +#define QZ_SLASH 0x2C +/* These are the same as the left versions - use left by default */ +#if 0 +#define QZ_RSHIFT 0x38 +#endif +#define QZ_UP 0x7E +#define QZ_KP1 0x53 +#define QZ_KP2 0x54 +#define QZ_KP3 0x55 +#define QZ_KP_ENTER 0x4C +#define QZ_LCTRL 0x3B +#define QZ_LALT 0x3A +#define QZ_LMETA 0x37 +#define QZ_SPACE 0x31 +/* These are the same as the left versions - use left by default */ +#if 0 +#define QZ_RMETA 0x37 +#define QZ_RALT 0x3A +#define QZ_RCTRL 0x3B +#endif +#define QZ_LEFT 0x7B +#define QZ_DOWN 0x7D +#define QZ_RIGHT 0x7C +#define QZ_KP0 0x52 +#define QZ_KP_PERIOD 0x41 + +/* Wierd, these keys are on my iBook under MacOS X */ +#define QZ_IBOOK_ENTER 0x34 +#define QZ_IBOOK_LEFT 0x3B +#define QZ_IBOOK_RIGHT 0x3C +#define QZ_IBOOK_DOWN 0x3D +#define QZ_IBOOK_UP 0x3E +#define KEY_ENTER 13 +#define KEY_TAB 9 + +#define KEY_BASE 0x100 + +/* Function keys */ +#define KEY_F (KEY_BASE+64) + +/* Control keys */ +#define KEY_CTRL (KEY_BASE) +#define KEY_BACKSPACE (KEY_CTRL+0) +#define KEY_DELETE (KEY_CTRL+1) +#define KEY_INSERT (KEY_CTRL+2) +#define KEY_HOME (KEY_CTRL+3) +#define KEY_END (KEY_CTRL+4) +#define KEY_PAGE_UP (KEY_CTRL+5) +#define KEY_PAGE_DOWN (KEY_CTRL+6) +#define KEY_ESC (KEY_CTRL+7) + +/* Control keys short name */ +#define KEY_BS KEY_BACKSPACE +#define KEY_DEL KEY_DELETE +#define KEY_INS KEY_INSERT +#define KEY_PGUP KEY_PAGE_UP +#define KEY_PGDOWN KEY_PAGE_DOWN +#define KEY_PGDWN KEY_PAGE_DOWN + +/* Cursor movement */ +#define KEY_CRSR (KEY_BASE+16) +#define KEY_RIGHT (KEY_CRSR+0) +#define KEY_LEFT (KEY_CRSR+1) +#define KEY_DOWN (KEY_CRSR+2) +#define KEY_UP (KEY_CRSR+3) + +/* Multimedia keyboard/remote keys */ +#define KEY_MM_BASE (0x100+384) +#define KEY_POWER (KEY_MM_BASE+0) +#define KEY_MENU (KEY_MM_BASE+1) +#define KEY_PLAY (KEY_MM_BASE+2) +#define KEY_PAUSE (KEY_MM_BASE+3) +#define KEY_PLAYPAUSE (KEY_MM_BASE+4) +#define KEY_STOP (KEY_MM_BASE+5) +#define KEY_FORWARD (KEY_MM_BASE+6) +#define KEY_REWIND (KEY_MM_BASE+7) +#define KEY_NEXT (KEY_MM_BASE+8) +#define KEY_PREV (KEY_MM_BASE+9) +#define KEY_VOLUME_UP (KEY_MM_BASE+10) +#define KEY_VOLUME_DOWN (KEY_MM_BASE+11) +#define KEY_MUTE (KEY_MM_BASE+12) + +/* Keypad keys */ +#define KEY_KEYPAD (KEY_BASE+32) +#define KEY_KP0 (KEY_KEYPAD+0) +#define KEY_KP1 (KEY_KEYPAD+1) +#define KEY_KP2 (KEY_KEYPAD+2) +#define KEY_KP3 (KEY_KEYPAD+3) +#define KEY_KP4 (KEY_KEYPAD+4) +#define KEY_KP5 (KEY_KEYPAD+5) +#define KEY_KP6 (KEY_KEYPAD+6) +#define KEY_KP7 (KEY_KEYPAD+7) +#define KEY_KP8 (KEY_KEYPAD+8) +#define KEY_KP9 (KEY_KEYPAD+9) +#define KEY_KPDEC (KEY_KEYPAD+10) +#define KEY_KPINS (KEY_KEYPAD+11) +#define KEY_KPDEL (KEY_KEYPAD+12) +#define KEY_KPENTER (KEY_KEYPAD+13) + +/* Special keys */ +#define KEY_INTERN (0x1000) +#define KEY_CLOSE_WIN (KEY_INTERN+0) diff --git a/emu/MacOSX/mkfile b/emu/MacOSX/mkfile new file mode 100644 index 00000000..5f716701 --- /dev/null +++ b/emu/MacOSX/mkfile @@ -0,0 +1,63 @@ +SYSTARG=MacOSX +#OBJTYPE=power +<../../mkconfig +SYSTARG=MacOSX +#OBJTYPE=power + +#Configurable parameters + +CONF=emu #default configuration +CONFLIST=emu +CLEANCONFLIST= + +INSTALLDIR=$ROOT/$SYSTARG/$OBJTYPE/bin #path of directory where kernel is installed + +#end configurable parameters + +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE #set vars based on target system + +<| $SHELLNAME ../port/mkdevlist $CONF #sets $IP, $DEVS, $PORT, $LIBS + +OBJ=\ + asm-$OBJTYPE.$O\ + os.$O\ + $CONF.root.$O\ + lock.$O\ + $DEVS\ + $PORT\ + +HFILES=\ + +CFLAGS='-DROOT="'$ROOT'"'\ + '-DOBJTYPE="'$OBJTYPE'"'\ + -DEMU -I. -I../port\ + -I$ROOT/$SYSTARG/$OBJTYPE/include\ + -I$ROOT/include -I$ROOT/libinterp\ + $CTHREADFLAGS $CFLAGS $EMUOPTIONS\ + +KERNDATE=`{$NDATE} + +LDFLAGS=$LDFLAGS -L/usr/X11R6/lib + +SYSLIBS= \ + -lm\ + -framework Carbon -framework QuickTime\ + -lpthread\ + -framework CoreFoundation\ + -framework IOKit\ +# -framework ApplicationServices\ + +default:V: $O.$CONF + + +$O.$CONF: $OBJ $CONF.c $CONF.root.h $LIBFILES + $CC $CFLAGS -DKERNDATE=$KERNDATE $CONF.c + $LD $LDFLAGS -o $target $OBJ $CONF.$O $LIBFILES $SYSLIBS + +install:V: $O.$CONF + cp $O.$CONF $INSTALLDIR/$CONF + +<../port/portmkfile + +ipif.c:N: ../FreeBSD/ipif.c +devfs.c:N: ../port/devfs-posix.c diff --git a/emu/MacOSX/mkfile-g b/emu/MacOSX/mkfile-g new file mode 100644 index 00000000..c1f9fa4b --- /dev/null +++ b/emu/MacOSX/mkfile-g @@ -0,0 +1,62 @@ +SYSTARG=MacOSX +#OBJTYPE=power +<../../mkconfig +SYSTARG=MacOSX +#OBJTYPE=power + +#Configurable parameters + +CONF=emu #default configuration +CONFLIST=emu +CLEANCONFLIST= + +INSTALLDIR=$ROOT/$SYSTARG/$OBJTYPE/bin #path of directory where kernel is installed + +#end configurable parameters + +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE #set vars based on target system + +<| $SHELLNAME ../port/mkdevlist $CONF #sets $IP, $DEVS, $PORT, $LIBS + +OBJ=\ + asm-$OBJTYPE.$O\ + os.$O\ + $CONF.root.$O\ + lock.$O\ + $DEVS\ + $PORT\ + +HFILES=\ + +CFLAGS='-DROOT="'$ROOT'"'\ + '-DOBJTYPE="'$OBJTYPE'"'\ + -DEMU -I. -I../port\ + -I$ROOT/$SYSTARG/$OBJTYPE/include\ + -I$ROOT/include -I$ROOT/libinterp\ + $CTHREADFLAGS $CFLAGS $EMUOPTIONS\ + +KERNDATE=`{$NDATE} + +LDFLAGS=$LDFLAGS -L/usr/X11R6/lib + +SYSLIBS= \ + -lm\ + -lpthread\ + -framework CoreFoundation\ + -framework IOKit\ +# -framework ApplicationServices\ + +default:V: $O.$CONF + + +$O.$CONF: $OBJ $CONF.c $CONF.root.h $LIBFILES + $CC $CFLAGS -DKERNDATE=$KERNDATE $CONF.c + $LD $LDFLAGS -o $target $OBJ $CONF.$O $LIBFILES $SYSLIBS + +install:V: $O.$CONF + cp $O.$CONF $INSTALLDIR/$CONF + +<../port/portmkfile + +ipif.c:N: ../FreeBSD/ipif.c +devfs.c:N: ../port/devfs-posix.c diff --git a/emu/MacOSX/mkfile-x11 b/emu/MacOSX/mkfile-x11 new file mode 100644 index 00000000..25fb99c6 --- /dev/null +++ b/emu/MacOSX/mkfile-x11 @@ -0,0 +1,64 @@ +SYSTARG=MacOSX +#OBJTYPE=power +<../../mkconfig +SYSTARG=MacOSX +#OBJTYPE=power + +#Configurable parameters + +CONF=emu #default configuration +CONFLIST=emu +CLEANCONFLIST= + +INSTALLDIR=$ROOT/$SYSTARG/$OBJTYPE/bin #path of directory where kernel is installed + +#end configurable parameters + +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE #set vars based on target system + +<| $SHELLNAME ../port/mkdevlist $CONF #sets $IP, $DEVS, $PORT, $LIBS + +OBJ=\ + asm-$OBJTYPE.$O\ + os.$O\ + win-x11a.$O\ + $CONF.root.$O\ + lock.$O\ + $DEVS\ + $PORT\ + +HFILES=\ + +CFLAGS='-DROOT="'$ROOT'"'\ + '-DOBJTYPE="'$OBJTYPE'"'\ + -DEMU -I. -I../port\ + -I$ROOT/$SYSTARG/$OBJTYPE/include\ + -I$ROOT/include -I$ROOT/libinterp\ + $CTHREADFLAGS $CFLAGS $EMUOPTIONS\ + -I/usr/X11R6/include + +KERNDATE=`{$NDATE} + +LDFLAGS=$LDFLAGS -L/usr/X11R6/lib + +SYSLIBS= \ + -lm -lX11 -lXext\ + -lpthread\ + -framework CoreFoundation\ + -framework IOKit\ +# -framework ApplicationServices\ + +default:V: $O.$CONF + + +$O.$CONF: $OBJ $CONF.c $CONF.root.h $LIBFILES + $CC $CFLAGS -DKERNDATE=$KERNDATE $CONF.c + $LD $LDFLAGS -o $target $OBJ $CONF.$O $LIBFILES $SYSLIBS + +install:V: $O.$CONF + cp $O.$CONF $INSTALLDIR/$CONF + +<../port/portmkfile + +ipif.c:N: ../FreeBSD/ipif.c +devfs.c:N: ../port/devfs-posix.c diff --git a/emu/MacOSX/os.c b/emu/MacOSX/os.c new file mode 100644 index 00000000..3363b5ad --- /dev/null +++ b/emu/MacOSX/os.c @@ -0,0 +1,647 @@ +/* + * Loosely based on FreeBSD/os.c and Solaris/os.c + * Copyright © 1998, 1999 Lucent Technologies Inc. All rights reserved. + * Revisions Copyright © 1999, 2000 Vita Nuova Limited. All rights reserved. + * Revisions Copyright © 2002, 2003 Corpus Callosum Corporation. All rights reserved. + */ + +#include "dat.h" +#include "fns.h" +#include "error.h" + +#undef _POSIX_C_SOURCE +#undef getwd + +#include <unistd.h> +#include <pthread.h> +#include <time.h> +#include <termios.h> +#include <signal.h> +#include <pwd.h> +#include <sys/resource.h> +#include <sys/time.h> + +#include <sys/socket.h> +#include <sched.h> +#include <errno.h> +#include <sys/ucontext.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <mach/mach_init.h> +#include <mach/task.h> +#include <mach/vm_map.h> + +#if defined(__ppc__) +#include <architecture/ppc/cframe.h> +#endif + +enum +{ + DELETE = 0x7F +}; +char *hosttype = "MacOSX"; +char *cputype = OBJTYPE; + +static pthread_key_t prdakey; + +extern int dflag; + +Proc * +getup(void) { + return (Proc *)pthread_getspecific(prdakey); +} + +/* Pthread version */ +void +pexit(char *msg, int t) +{ + Osenv *e; + Proc *p; + + USED(t); + USED(msg); + + lock(&procs.l); + p = up; + if(p->prev) + p->prev->next = p->next; + else + procs.head = p->next; + + if(p->next) + p->next->prev = p->prev; + else + procs.tail = p->prev; + unlock(&procs.l); + + if(0) + print("pexit: %s: %s\n", p->text, msg); + + e = p->env; + if(e != nil) { + closefgrp(e->fgrp); + closepgrp(e->pgrp); + closeegrp(e->egrp); + closesigs(e->sigs); + } + free(e->user); + free(p->prog); + free(p); + pthread_exit(0); +} + +void +trapBUS(int signo) +{ + USED(signo); + disfault(nil, "Bus error"); +} + +void +trapUSR1(int signo) +{ + USED(signo); + + if(up->type != Interp) /* Used to unblock pending I/O */ + return; + if(up->intwait == 0) /* Not posted so its a sync error */ + disfault(nil, Eintr); /* Should never happen */ + + up->intwait = 0; /* Clear it so the proc can continue */ +} + +void +trapILL(int signo) +{ + USED(signo); + disfault(nil, "Illegal instruction"); +} + +/* from geoff collyer's port */ +void +printILL(int sig, siginfo_t *siginfo, void *v) +{ + USED(sig); + USED(v); + panic("Illegal instruction with code=%d at address=%x, opcode=%x.\n" + ,siginfo->si_code, siginfo->si_addr,*(char*)siginfo->si_addr); +} + +void +trapSEGV(int signo) +{ + USED(signo); + disfault(nil, "Segmentation violation"); +} + +void +trapFPE(int signo) +{ + USED(signo); + disfault(nil, "Floating point exception"); +} + +static void +setsigs(void) +{ + struct sigaction act; + + memset(&act, 0 , sizeof(act)); + + /* + * For the correct functioning of devcmd in the + * face of exiting slaves + */ + signal(SIGPIPE, SIG_IGN); + if(signal(SIGTERM, SIG_IGN) != SIG_IGN) + signal(SIGTERM, cleanexit); + + act.sa_handler=trapUSR1; + sigaction(SIGUSR1, &act, nil); + + if(sflag == 0) { + act.sa_handler = trapBUS; + sigaction(SIGBUS, &act, nil); + act.sa_handler = trapILL; + sigaction(SIGILL, &act, nil); + act.sa_handler = trapSEGV; + sigaction(SIGSEGV, &act, nil); + act.sa_handler = trapFPE; + sigaction(SIGFPE, &act, nil); + if(signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, cleanexit); + } else { + act.sa_sigaction = printILL; + act.sa_flags=SA_SIGINFO; + sigaction(SIGILL, &act, nil); + } +} + + +void * +tramp(void *arg) +{ + Proc *p = arg; + p->sigid = (int)pthread_self(); + if(pthread_setspecific(prdakey, arg)) { + print("set specific data failed in tramp\n"); + pthread_exit(0); + } + p->func(p->arg); + pexit("{Tramp}", 0); + return NULL; +} + +int +kproc(char *name, void (*func)(void*), void *arg, int flags) +{ + pthread_t thread; + Proc *p; + Pgrp *pg; + Fgrp *fg; + Egrp *eg; + + pthread_attr_t attr; + + p = newproc(); + if(p == nil) + panic("kproc: no memory"); + + if(flags & KPDUPPG) { + pg = up->env->pgrp; + incref(&pg->r); + p->env->pgrp = pg; + } + if(flags & KPDUPFDG) { + fg = up->env->fgrp; + incref(&fg->r); + p->env->fgrp = fg; + } + if(flags & KPDUPENVG) { + eg = up->env->egrp; + incref(&eg->r); + p->env->egrp = eg; + } + + p->env->uid = up->env->uid; + p->env->gid = up->env->gid; + kstrdup(&p->env->user, up->env->user); + + strcpy(p->text, name); + + p->func = func; + p->arg = arg; + + lock(&procs.l); + if(procs.tail != nil) { + p->prev = procs.tail; + procs.tail->next = p; + } else { + procs.head = p; + p->prev = nil; + } + procs.tail = p; + unlock(&procs.l); + + up->kid = p; + + if((pthread_attr_init(&attr))== -1) + panic("pthread_attr_init failed"); + + errno=0; + pthread_attr_setschedpolicy(&attr,SCHED_OTHER); + if(errno) + panic("pthread_attr_setschedpolicy failed"); + + pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + if(pthread_create(&thread, &attr, tramp, p)) + panic("thr_create failed\n"); + pthread_attr_destroy(&attr); + + return (int)thread; +} + +int +segflush(void *va, ulong len) +{ + kern_return_t err; + vm_machine_attribute_val_t value = MATTR_VAL_ICACHE_FLUSH; + + err = vm_machine_attribute( (vm_map_t)mach_task_self(), + (vm_address_t)va, + (vm_size_t)len, + MATTR_CACHE, + &value); + if (err != KERN_SUCCESS) { + print("segflush: failure (%d) address %lud\n", err, va); + } + return (int)err; +} + +/* from geoff collyer's port +invalidate instruction cache and write back data cache from a to a+n-1, +at least. + +void +segflush(void *a, ulong n) +{ + ulong *p; + + // paranoia, flush the world + __asm__("isync\n\t" + "eieio\n\t" + : // no output + : + ); + // cache blocks are often eight words (32 bytes) long, sometimes 16 bytes. + // need to determine it dynamically? + for (p = (ulong *)((ulong)a & ~3UL); (char *)p < (char *)a + n; p++) + __asm__("dcbst 0,%0\n\t" // not dcbf, which writes back, then invalidates + "icbi 0,%0\n\t" + : // no output + : "ar" (p) + ); + __asm__("isync\n\t" + "eieio\n\t" + : // no output + : + ); +} +*/ + +void +oshostintr(Proc *p) +{ + pthread_kill((pthread_t)p->sigid, SIGUSR1); +} + +static ulong erendezvous(void*, ulong); + +void +osblock(void) +{ + erendezvous(up, 0); +} + +void +osready(Proc *p) +{ + erendezvous(p, 0); +} + +void +oslongjmp(void *regs, osjmpbuf env, int val) +{ + USED(regs); + siglongjmp(env, val); +} + +struct termios tinit; + +static void +termset(void) +{ + struct termios t; + + tcgetattr(0, &t); + tinit = t; + t.c_lflag &= ~(ICANON|ECHO|ISIG); + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &t); +} + +static void +termrestore(void) +{ + tcsetattr(0, TCSANOW, &tinit); +} + + +void +cleanexit(int x) +{ + USED(x); + + if(up->intwait) { + up->intwait = 0; + return; + } + + if(dflag == 0) + termrestore(); + + exit(0); +} + +void +osreboot(char *file, char **argv) +{ + if(dflag == 0) + termrestore(); + execvp(file, argv); + panic("reboot failure"); +} + +int gidnobody= -1, uidnobody= -1; + +void +getnobody() +{ + struct passwd *pwd; + + if((pwd = getpwnam("nobody"))) { + uidnobody = pwd->pw_uid; + gidnobody = pwd->pw_gid; + } +} + +/* Pthread version */ +static pthread_mutex_t rendezvouslock; +static pthread_mutexattr_t *pthread_mutexattr_default = NULL; + +void +libinit(char *imod) +{ + struct passwd *pw; + Proc *p; + char sys[64]; + + setsid(); + + // setup personality + gethostname(sys, sizeof(sys)); + kstrdup(&ossysname, sys); + getnobody(); + + if(dflag == 0) + termset(); + + setsigs(); + + if(pthread_mutex_init(&rendezvouslock, pthread_mutexattr_default)) + panic("pthread_mutex_init"); + + if(pthread_key_create(&prdakey,NULL)) + print("key_create failed\n"); + + p = newproc(); + if(pthread_setspecific(prdakey, p)) + panic("set specific thread data failed\n"); + + pw = getpwuid(getuid()); + if(pw != nil) + kstrdup(&eve, pw->pw_name); + else + print("cannot getpwuid\n"); + + up->env->uid = getuid(); + up->env->gid = getgid(); + + emuinit(imod); +} + +int +readkbd(void) +{ + int n; + char buf[1]; + + n = read(0, buf, sizeof(buf)); + if(n < 0) + print("keyboard close (n=%d, %s)\n", n, strerror(errno)); + if(n <= 0) + pexit("keyboard thread", 0); + + switch(buf[0]) { + case '\r': + buf[0] = '\n'; + break; + case DELETE: + cleanexit(0); + break; + } + return buf[0]; +} + +enum +{ + NHLOG = 7, + NHASH = (1<<NHLOG) +}; + +typedef struct Tag Tag; +struct Tag +{ + void* tag; + ulong val; + pthread_cond_t cv; + Tag* next; +}; + +static Tag* ht[NHASH]; +static Tag* ft; +//static Lock hlock; + +static ulong +erendezvous(void *tag, ulong value) +{ + int h; + ulong rval; + Tag *t, **l, *f; + + h = (ulong)tag & (NHASH-1); + +// lock(&hlock); + pthread_mutex_lock(&rendezvouslock); + l = &ht[h]; + for(t = ht[h]; t; t = t->next) { + if(t->tag == tag) { + rval = t->val; + t->val = value; + t->tag = 0; + pthread_mutex_unlock(&rendezvouslock); +// unlock(&hlock); + if(pthread_cond_signal(&(t->cv))) + panic("pthread_cond_signal"); + return rval; + } + } + + t = ft; + if(t == 0) { + t = malloc(sizeof(Tag)); + if(t == nil) + panic("rendezvous: no memory"); + if(pthread_cond_init(&(t->cv), NULL)) { + print("pthread_cond_init (errno: %s) \n", strerror(errno)); + panic("pthread_cond_init"); + } + } else + ft = t->next; + + t->tag = tag; + t->val = value; + t->next = *l; + *l = t; +// pthread_mutex_unlock(&rendezvouslock); +// unlock(&hlock); + + while(t->tag != nil) + pthread_cond_wait(&(t->cv),&rendezvouslock); + +// pthread_mutex_lock(&rendezvouslock); +// lock(&hlock); + rval = t->val; + for(f = *l; f; f = f->next){ + if(f == t) { + *l = f->next; + break; + } + l = &f->next; + } + t->next = ft; + ft = t; + pthread_mutex_unlock(&rendezvouslock); +// unlock(&hlock); + + return rval; +} + +/* + * Return an abitrary millisecond clock time + */ +long +osmillisec(void) +{ + static long sec0 = 0, usec0; + struct timeval t; + + if(gettimeofday(&t, NULL)<0) + return(0); + if(sec0==0) { + sec0 = t.tv_sec; + usec0 = t.tv_usec; + } + return((t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000); +} + +/* + * Return the time since the epoch in nanoseconds and microseconds + * The epoch is defined at 1 Jan 1970 + */ +vlong +osnsec(void) +{ + struct timeval t; + + gettimeofday(&t, nil); + return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000; +} + +vlong +osusectime(void) +{ + struct timeval t; + + gettimeofday(&t, nil); + return (vlong)t.tv_sec * 1000000 + t.tv_usec; +} + + +int +osmillisleep(ulong milsec) +{ + struct timespec time; + time.tv_sec = milsec / 1000; + time.tv_nsec = (milsec % 1000) * 1000000; + nanosleep(&time, nil); + return 0; +} + +int +limbosleep(ulong milsec) +{ + return osmillisleep(milsec); +} + +void +osyield(void) +{ + pthread_yield_np(); + // sched_yield(); +} + +void +ospause(void) +{ + for(;;) + pause(); +} + +void +oslopri(void) +{ +// pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param); + setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4); +} + +__typeof__(sbrk(0)) +sbrk(int size) +{ + void *brk; + kern_return_t err; + + err = vm_allocate( (vm_map_t) mach_task_self(), + (vm_address_t *)&brk, + size, + VM_FLAGS_ANYWHERE); + if (err != KERN_SUCCESS) + brk = (void*)-1; + + return brk; +} diff --git a/emu/MacOSX/win.c b/emu/MacOSX/win.c new file mode 100644 index 00000000..41ca8d9d --- /dev/null +++ b/emu/MacOSX/win.c @@ -0,0 +1,755 @@ +// in this file, _Rect is os x Rect, +// _Point is os x Point +#define Point _Point +#define Rect _Rect + +#include <Carbon/Carbon.h> +#include <QuickTime/QuickTime.h> // for full screen + +#undef Rect +#undef Point + +#undef nil + +#include "dat.h" +#include "fns.h" +#undef log2 +#include <draw.h> +#include <memdraw.h> +#include "cursor.h" +#include "keyboard.h" +#include "keycodes.h" + +#define Kup Up +#define Kleft Left +#define Kdown Down +#define Kright Right +#define Kalt LAlt +#define Kctl LCtrl +#define Kshift LShift +#define Kpgup Pgup +#define Kpgdown Pgdown +#define Khome Home +#define Kins Ins +#define Kend End + +#define rWindowResource 128 + +extern void flushmemscreen(Rectangle); + +Memimage *gscreen; + +static int readybit; +static Rendez rend; +static int triedscreen; + +/// +// menu +// +static MenuRef windMenu; +static MenuRef viewMenu; + +enum { + kQuitCmd = 1, + kFullScreenCmd = 2, +}; + +static WindowGroupRef winGroup = NULL; +static WindowRef theWindow = NULL; +static CGContextRef context; +static CGDataProviderRef dataProviderRef; +static CGImageRef fullScreenImage; +static CGRect devRect; +static CGRect bounds; +static PasteboardRef appleclip; +static _Rect winRect; + +static Boolean altPressed = false; +static Boolean button2 = false; +static Boolean button3 = false; + +static Boolean needflush = false; + + +static int +isready(void*a) +{ + return readybit; +} + +CGContextRef QuartzContext; + +static OSStatus MainWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData); +static OSStatus MainWindowCommandHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData); + +static void winproc(void *a); +static void flushproc(void *a); + +void +screeninit(void) +{ + int fmt; + int dx, dy; + ProcessSerialNumber psn = { 0, kCurrentProcess }; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + SetFrontProcess(&psn); + + fmt = XBGR32; //XRGB32; + + devRect = CGDisplayBounds(CGMainDisplayID()); +// devRect.origin.x = 0; +// devRect.origin.y = 0; +// devRect.size.width = 1024; +// devRect.size.height = 768; + dx = devRect.size.width; + dy = devRect.size.height; + + if(1){ /* TO DO: new dev draw for changing screen size */ + dx = Xsize; + dy = Ysize; + } + + gscreen = allocmemimage(Rect(0,0,dx,dy), fmt); + dataProviderRef = CGDataProviderCreateWithData(0, gscreen->data->bdata, + dx * dy * 4, 0); + fullScreenImage = CGImageCreate(dx, dy, 8, 32, dx * 4, + CGColorSpaceCreateDeviceRGB(), + kCGImageAlphaNoneSkipLast, + dataProviderRef, 0, 0, kCGRenderingIntentDefault); + + kproc("osxscreen", winproc, nil, 0); + kproc("osxflush", flushproc, nil, 0); + Sleep(&rend, isready, nil); +} + +void +window_resized(void) +{ + GetWindowBounds(theWindow, kWindowContentRgn, &winRect); + + bounds = CGRectMake(0, 0, winRect.right-winRect.left, winRect.bottom - winRect.top); +} + +static void +flushproc(void *a) +{ + for(;;) { + if(needflush) { + drawqlock(); + QDBeginCGContext(GetWindowPort(theWindow), &context); + CGContextFlush(context); + QDEndCGContext(GetWindowPort(theWindow), &context); + needflush = false; + drawqunlock(); + } + usleep(33333); + } +} + +static void +winproc(void *a) +{ + MenuItemIndex index; + int dx, dy; + + winRect.left = 30; + winRect.top = 60; + dx = devRect.size.width*0.75; /* devRect is full screen; take only most of it */ + dy = devRect.size.height*0.75; + if(1){ /* TO DO */ + dx = Xsize; + dy = Ysize; + } + winRect.bottom = winRect.top + dy; + winRect.right = winRect.left + dx; + + ClearMenuBar(); + InitCursor(); + + CreateStandardWindowMenu(0, &windMenu); + InsertMenu(windMenu, 0); + + CreateNewMenu(1004, 0, &viewMenu); + SetMenuTitleWithCFString(viewMenu, CFSTR("View")); + AppendMenuItemTextWithCFString(viewMenu, CFSTR("Full Screen"), 0, + kFullScreenCmd, &index); + SetMenuItemCommandKey(viewMenu, index, 0, 'F'); + AppendMenuItemTextWithCFString(viewMenu, CFSTR("ctrl-opt to return"), + kMenuItemAttrDisabled, + kFullScreenCmd, &index); + InsertMenu(viewMenu, GetMenuID(windMenu)); + + DrawMenuBar(); + uint32_t windowAttrs = 0 + | kWindowCloseBoxAttribute + | kWindowCollapseBoxAttribute +// | kWindowResizableAttribute // TO DO + | kWindowStandardHandlerAttribute +// | kWindowFullZoomAttribute // TO DO + ; + + CreateNewWindow(kDocumentWindowClass, windowAttrs, &winRect, &theWindow); + CreateWindowGroup(0, &winGroup); + SetWindowGroup(theWindow, winGroup); + + SetWindowTitleWithCFString(theWindow, CFSTR("Inferno")); + + if(PasteboardCreate(kPasteboardClipboard, &appleclip) != noErr) + sysfatal("pasteboard create failed"); + + const EventTypeSpec commands[] = { + { kEventClassWindow, kEventWindowClosed }, + { kEventClassWindow, kEventWindowBoundsChanged }, + { kEventClassCommand, kEventCommandProcess } + }; + const EventTypeSpec events[] = { + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyModifiersChanged }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassMouse, kEventMouseWheelMoved }, + }; + + InstallApplicationEventHandler ( + NewEventHandlerUPP (MainWindowEventHandler), + GetEventTypeCount(events), + events, + NULL, + NULL); + InstallWindowEventHandler ( + theWindow, + NewEventHandlerUPP (MainWindowCommandHandler), + GetEventTypeCount(commands), + commands, + theWindow, + NULL); + + ShowWindow(theWindow); + ShowMenuBar(); + window_resized(); + SelectWindow(theWindow); + // Run the event loop + readybit = 1; + Wakeup(&rend); + RunApplicationEventLoop(); + +} + +static int +convert_key(UInt32 key, UInt32 charcode) +{ + switch(key) { + case QZ_IBOOK_ENTER: + case QZ_RETURN: return '\n'; + case QZ_ESCAPE: return 27; + case QZ_BACKSPACE: return '\b'; + case QZ_LALT: return Kalt; + case QZ_LCTRL: return Kctl; + case QZ_LSHIFT: return Kshift; + case QZ_F1: return KF+1; + case QZ_F2: return KF+2; + case QZ_F3: return KF+3; + case QZ_F4: return KF+4; + case QZ_F5: return KF+5; + case QZ_F6: return KF+6; + case QZ_F7: return KF+7; + case QZ_F8: return KF+8; + case QZ_F9: return KF+9; + case QZ_F10: return KF+10; + case QZ_F11: return KF+11; + case QZ_F12: return KF+12; + case QZ_INSERT: return Kins; + case QZ_DELETE: return 0x7F; + case QZ_HOME: return Khome; + case QZ_END: return Kend; + case QZ_KP_PLUS: return '+'; + case QZ_KP_MINUS: return '-'; + case QZ_TAB: return '\t'; + case QZ_PAGEUP: return Kpgup; + case QZ_PAGEDOWN: return Kpgdown; + case QZ_UP: return Kup; + case QZ_DOWN: return Kdown; + case QZ_LEFT: return Kleft; + case QZ_RIGHT: return Kright; + case QZ_KP_MULTIPLY: return '*'; + case QZ_KP_DIVIDE: return '/'; + case QZ_KP_ENTER: return '\n'; + case QZ_KP_PERIOD: return '.'; + case QZ_KP0: return '0'; + case QZ_KP1: return '1'; + case QZ_KP2: return '2'; + case QZ_KP3: return '3'; + case QZ_KP4: return '4'; + case QZ_KP5: return '5'; + case QZ_KP6: return '6'; + case QZ_KP7: return '7'; + case QZ_KP8: return '8'; + case QZ_KP9: return '9'; + default: return charcode; + } +} + +void +sendbuttons(int b, int x, int y) +{ + mousetrack(b, x, y, 0); +} + +static Ptr fullScreenRestore; +static int amFullScreen = 0; +static WindowRef oldWindow = NULL; + +static void +leave_full_screen(void) +{ + if (0 && amFullScreen) { + EndFullScreen(fullScreenRestore, 0); + theWindow = oldWindow; + ShowWindow(theWindow); + amFullScreen = 0; + window_resized(); + Rectangle rect = { { 0, 0 }, { bounds.size.width, bounds.size.height} }; + drawqlock(); + flushmemscreen(rect); + drawqunlock(); + } +} + +static void +full_screen(void) +{ + if (0 && !amFullScreen) { + oldWindow = theWindow; + HideWindow(theWindow); + BeginFullScreen(&fullScreenRestore, 0, 0, 0, &theWindow, 0, 0); + amFullScreen = 1; + window_resized(); + Rectangle rect = { { 0, 0 }, + { bounds.size.width, + bounds.size.height} }; + drawqlock(); + flushmemscreen(rect); + drawqunlock(); + } +} + +static OSStatus +MainWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData) +{ + OSStatus result = noErr; + result = CallNextEventHandler(nextHandler, event); + UInt32 class = GetEventClass (event); + UInt32 kind = GetEventKind (event); + static uint32_t mousebuttons = 0; // bitmask of buttons currently down + static uint32_t mouseX = 0; + static uint32_t mouseY = 0; + + if(class == kEventClassKeyboard) { + char macCharCodes; + UInt32 macKeyCode; + UInt32 macKeyModifiers; + + GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, + NULL, sizeof(macCharCodes), NULL, &macCharCodes); + GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, + sizeof(macKeyCode), NULL, &macKeyCode); + GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, + sizeof(macKeyModifiers), NULL, &macKeyModifiers); + switch(kind) { + case kEventRawKeyModifiersChanged: + if (macKeyModifiers == (controlKey | optionKey)) leave_full_screen(); + + switch(macKeyModifiers & (optionKey | cmdKey)) { + case (optionKey | cmdKey): + /* due to chording we need to handle the case when both + * modifier keys are pressed at the same time. + * currently it's only 2-3 snarf and the 3-2 noop + */ + altPressed = true; + if(mousebuttons & 1 || mousebuttons & 2 || mousebuttons & 4) { + mousebuttons |= 2; /* set button 2 */ + mousebuttons |= 4; /* set button 3 */ + button2 = true; + button3 = true; + sendbuttons(mousebuttons, mouseX, mouseY); + } + break; + case optionKey: + altPressed = true; + if(mousebuttons & 1 || mousebuttons & 4) { + mousebuttons |= 2; /* set button 2 */ + button2 = true; + sendbuttons(mousebuttons, mouseX, mouseY); + } + break; + case cmdKey: + if(mousebuttons & 1 || mousebuttons & 2) { + mousebuttons |= 4; /* set button 3 */ + button3 = true; + sendbuttons(mousebuttons, mouseX, mouseY); + }else + gkbdputc(gkbdq, Latin); + break; + case 0: + default: + if(button2 || button3) { + if(button2) { + mousebuttons &= ~2; /* clear button 2 */ + button2 = false; + altPressed = false; + } + if(button3) { + mousebuttons &= ~4; /* clear button 3 */ + button3 = false; + } + sendbuttons(mousebuttons, mouseX, mouseY); + } + if(altPressed) { + gkbdputc(gkbdq, Kalt); + altPressed = false; + } + break; + } + break; + case kEventRawKeyDown: + case kEventRawKeyRepeat: + if(macKeyModifiers != cmdKey) { + int key; + key = convert_key(macKeyCode, macCharCodes); + if(key != -1) + gkbdputc(gkbdq, key); + }else + result = eventNotHandledErr; + break; + default: + break; + } + } + else if(class == kEventClassMouse) { + _Point mousePos; + + GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, + 0, sizeof mousePos, 0, &mousePos); + + switch(kind) { + case kEventMouseWheelMoved: + { + int32_t wheeldelta; + GetEventParameter(event,kEventParamMouseWheelDelta,typeSInt32, + 0,sizeof(wheeldelta), 0, &wheeldelta); + mouseX = mousePos.h - winRect.left; + mouseY = mousePos.v - winRect.top; + sendbuttons(wheeldelta>0 ? 8 : 16, mouseX, mouseY); + break; + } + case kEventMouseUp: + case kEventMouseDown: + { + uint32_t buttons; + uint32_t modifiers; + GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, + 0, sizeof(modifiers), 0, &modifiers); + GetEventParameter(event, kEventParamMouseChord, typeUInt32, + 0, sizeof buttons, 0, &buttons); + /* simulate other buttons via alt/apple key. like x11 */ + if(modifiers & optionKey) { + mousebuttons = ((buttons & 1) ? 2 : 0); + altPressed = false; + } else if(modifiers & cmdKey) + mousebuttons = ((buttons & 1) ? 4 : 0); + else + mousebuttons = (buttons & 1); + + mousebuttons |= ((buttons & 2)<<1); + mousebuttons |= ((buttons & 4)>>1); + + } /* Fallthrough */ + case kEventMouseMoved: + case kEventMouseDragged: + mouseX = mousePos.h - winRect.left; + mouseY = mousePos.v - winRect.top; + sendbuttons(mousebuttons, mouseX, mouseY); + break; + default: + result = eventNotHandledErr; + break; + } + } + return result; +} + + +//default window command handler (from menus) +static OSStatus +MainWindowCommandHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData) +{ + OSStatus result = noErr; + UInt32 class = GetEventClass (event); + UInt32 kind = GetEventKind (event); + + result = CallNextEventHandler(nextHandler, event); + + if(class == kEventClassCommand) { + HICommand theHICommand; + GetEventParameter(event, kEventParamDirectObject, typeHICommand, + NULL, sizeof(HICommand), NULL, &theHICommand); + + switch(theHICommand.commandID) { + case kHICommandQuit: + cleanexit(0); + break; + + case kFullScreenCmd: + full_screen(); + break; + + default: + result = eventNotHandledErr; + break; + } + } else if(class == kEventClassWindow) { + WindowRef window; + _Rect rectPort = {0,0,0,0}; + + GetEventParameter(event, kEventParamDirectObject, typeWindowRef, + NULL, sizeof(WindowRef), NULL, &window); + + if(window) + GetPortBounds(GetWindowPort(window), &rectPort); + + switch(kind) { + case kEventWindowClosed: + theWindow = NULL; + cleanexit(0); // only one window + break; + + //resize window + case kEventWindowBoundsChanged: + window_resized(); + Rectangle rect = { { 0, 0 }, + { bounds.size.width, + bounds.size.height} }; + drawqlock(); + flushmemscreen(rect); + drawqunlock(); + break; + + default: + result = eventNotHandledErr; + break; + } + } + + return result; +} + +void +flushmemscreen(Rectangle r) +{ + CGRect rbounds; + + // sanity check. Trips from the initial "terminal" + if (r.max.x < r.min.x || r.max.y < r.min.y) + return; + + rbounds.size.width = r.max.x - r.min.x; + rbounds.size.height = r.max.y - r.min.y; + rbounds.origin.x = r.min.x; + rbounds.origin.y = r.min.y; + + if(rbounds.size.width <= 0 || rbounds.size.height <= 0) + return; + + QDBeginCGContext(GetWindowPort(theWindow), &context); + + // The sub-image is relative to our whole screen image. + CGImageRef subimg = CGImageCreateWithImageInRect(fullScreenImage, rbounds); + + // Drawing the sub-image is relative to the window. + rbounds.origin.y = winRect.bottom - winRect.top - r.min.y - rbounds.size.height; + CGContextDrawImage(context, rbounds, subimg); + CGImageRelease(subimg); + QDEndCGContext(GetWindowPort(theWindow), &context); + + needflush = true; +} + +uchar* +attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen) +{ + if(!triedscreen) { + triedscreen = 1; + screeninit(); /* TO DO: call this elsewhere? */ + } + *r = gscreen->r; + *chan = gscreen->chan; + *depth = gscreen->depth; + *width = gscreen->width; + *softscreen = 1; + + return gscreen->data->bdata; +} + +// PAL - no palette handling. Don't intend to either. +void +getcolor(ulong i, ulong *r, ulong *g, ulong *b) +{ + +// PAL: Certainly wrong to return a grayscale. + *r = i; + *g = i; + *b = i; +} + +void +setcolor(ulong index, ulong r, ulong g, ulong b) +{ + USED(index); USED(r); USED(g); USED(b); +} + +enum{ + SnarfSize= 100*1024 +}; + +static char snarf[3*SnarfSize+1]; +static Rune rsnarf[SnarfSize+1]; + +char* +clipread(void) +{ + CFDataRef cfdata; + OSStatus err = noErr; + ItemCount nitems; + int i; + char *s; + + // Wow. This is ridiculously complicated. + PasteboardSynchronize(appleclip); + if((err = PasteboardGetItemCount(appleclip, &nitems)) != noErr) { + fprint(2, "apple pasteboard GetItemCount failed - Error %d\n", err); + return 0; + } + + // Yes, based at 1. Silly API. + for(i = 1; i <= nitems; i++) { + PasteboardItemID itemID; + CFArrayRef flavorTypeArray; + CFIndex flavorCount; + + if((err = PasteboardGetItemIdentifier(appleclip, i, &itemID)) != noErr){ + fprint(2, "Can't get pasteboard item identifier: %d\n", err); + return 0; + } + + if((err = PasteboardCopyItemFlavors(appleclip, itemID, &flavorTypeArray))!=noErr){ + fprint(2, "Can't copy pasteboard item flavors: %d\n", err); + return 0; + } + + flavorCount = CFArrayGetCount(flavorTypeArray); + CFIndex flavorIndex; + for(flavorIndex = 0; flavorIndex < flavorCount; ++flavorIndex){ + CFStringRef flavorType; + flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex); + if (UTTypeConformsTo(flavorType, CFSTR("public.utf16-plain-text"))){ + if((err = PasteboardCopyItemFlavorData(appleclip, itemID, + CFSTR("public.utf16-plain-text"), &cfdata)) != noErr){ + fprint(2, "apple pasteboard CopyItem failed - Error %d\n", err); + return 0; + } + CFIndex length = CFDataGetLength(cfdata); + if (length > sizeof rsnarf) length = sizeof rsnarf; + CFDataGetBytes(cfdata, CFRangeMake(0, length), (uint8_t *)rsnarf); + snprint(snarf, sizeof snarf, "%.*S", length/sizeof(Rune), rsnarf); + for(s = snarf; *s; s++) + if(*s == '\r') + *s = '\n'; + CFRelease(cfdata); + return strdup(snarf); + } + } + } + return 0; +} + +int +clipwrite(char *snarf) +{ + CFDataRef cfdata; + PasteboardSyncFlags flags; + + runeseprint(rsnarf, rsnarf+nelem(rsnarf), "%s", snarf); + if(PasteboardClear(appleclip) != noErr){ + fprint(2, "apple pasteboard clear failed\n"); + return 0; + } + flags = PasteboardSynchronize(appleclip); + if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){ + fprint(2, "apple pasteboard cannot assert ownership\n"); + return 0; + } + cfdata = CFDataCreate(kCFAllocatorDefault, (uchar*)rsnarf, runestrlen(rsnarf)*2); + if(cfdata == nil){ + fprint(2, "apple pasteboard cfdatacreate failed\n"); + return 0; + } + if(PasteboardPutItemFlavor(appleclip, (PasteboardItemID)1, + CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){ + fprint(2, "apple pasteboard putitem failed\n"); + CFRelease(cfdata); + return 0; + } + CFRelease(cfdata); + return 1; +} + +void +setpointer(int x, int y) +{ + CGPoint pnt; + + pnt.x = x + winRect.left; + pnt.y = y + winRect.top; + CGWarpMouseCursorPosition(pnt); +} + +void +drawcursor(Drawcursor* c) +{ + Cursor crsr; + uchar *bc, *bs, *ps, *pm; + int i, j, h, w, bpl; + + if(c->data == nil || c->minx >= c->maxx){ + InitCursor(); + return; + } + memset(crsr.data, 0, sizeof(crsr.data)); + memset(crsr.mask, 0, sizeof(crsr.mask)); + ps = (uchar*)crsr.data; + pm = (uchar*)crsr.mask; + h = (c->maxy - c->miny)/2; /* bounds include both masks, strangely */ + bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 1); + if((w = bpl) > 2) + w = 2; + bc = c->data; + bs = c->data + h*bpl; + if(h > 16) + h = 16; + for(i = 0; i < h; i++){ + for(j = 0; j < w; j++){ + ps[j] = bs[j]; + pm[j] = bs[j] | bc[j]; + } + bs += bpl; + bc += bpl; + ps += 2; + pm += 2; + } + crsr.hotSpot.h = -c->hotx; + crsr.hotSpot.v = -c->hoty; + SetCursor(&crsr); +} |
