/* OSGLUXWN.c Copyright (C) 2009 Michael Hanni, Christian Bauer, Stephan Kochen, Paul C. Pratt, and others You can redistribute this file and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. You should have received a copy of the license along with this file; see the file COPYING. This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ /* Operating System GLUe for X WiNdow system All operating system dependent code for the X Window System should go here. This code is descended from Michael Hanni's X port of vMac, by Philip Cummins. I learned more about how X programs work by looking at other programs such as Basilisk II, the UAE Amiga Emulator, Bochs, QuakeForge, DooM Legacy, and the FLTK. A few snippets from them are used here. Drag and Drop support is based on the specification "XDND: Drag-and-Drop Protocol for the X Window System" developed by John Lindal at New Planet Software, and looking at included examples, one by Paul Sheer. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CNFGGLOB.h" #include "CNFGRAPI.h" #include "SYSDEPNS.h" #include "UTIL/ENDIANAC.h" #include "UI/MYOSGLUE.h" #include "STRCONST.h" /* --- some simple utilities --- */ GLOBALOSGLUPROC MoveBytes(anyp srcPtr, anyp destPtr, int32_t byteCount) { (void) memcpy((char *)destPtr, (char *)srcPtr, byteCount); } /* --- control mode and internationalization --- */ #define NeedCell2PlainAsciiMap 1 #include "LANG/INTLCHAR.h" LOCALVAR char *d_arg = NULL; LOCALVAR char *n_arg = NULL; #ifdef CanGetAppPath LOCALVAR char *app_parent = NULL; LOCALVAR char *app_name = NULL; #endif LOCALFUNC MacErr_t ChildPath(char *x, char *y, char **r) { MacErr_t err = mnvm_miscErr; int nx = strlen(x); int ny = strlen(y); { if ((nx > 0) && ('/' == x[nx - 1])) { --nx; } { int nr = nx + 1 + ny; char *p = malloc(nr + 1); if (p != NULL) { char *p2 = p; (void) memcpy(p2, x, nx); p2 += nx; *p2++ = '/'; (void) memcpy(p2, y, ny); p2 += ny; *p2 = 0; *r = p; err = mnvm_noErr; } } } return err; } #if IncludeSonyNew LOCALFUNC MacErr_t FindOrMakeChild(char *x, char *y, char **r) { MacErr_t err; struct stat folder_info; char *r0; if (mnvm_noErr == (err = ChildPath(x, y, &r0))) { if (0 != stat(r0, &folder_info)) { if (0 != mkdir(r0, S_IRWXU)) { err = mnvm_miscErr; } else { *r = r0; err = mnvm_noErr; } } else { if (! S_ISDIR(folder_info.st_mode)) { err = mnvm_miscErr; } else { *r = r0; err = mnvm_noErr; } } } return err; } #endif LOCALPROC MayFree(char *p) { if (NULL != p) { free(p); } } /* --- sending debugging info to file --- */ #if dbglog_HAVE #define dbglog_ToStdErr 0 #if ! dbglog_ToStdErr LOCALVAR FILE *dbglog_File = NULL; #endif LOCALFUNC bool dbglog_open0(void) { #if dbglog_ToStdErr return true; #else dbglog_File = fopen("dbglog.txt", "w"); return (NULL != dbglog_File); #endif } LOCALPROC dbglog_write0(char *s, uimr L) { #if dbglog_ToStdErr (void) fwrite(s, 1, L, stderr); #else if (dbglog_File != NULL) { (void) fwrite(s, 1, L, dbglog_File); } #endif } LOCALPROC dbglog_close0(void) { #if ! dbglog_ToStdErr if (dbglog_File != NULL) { fclose(dbglog_File); dbglog_File = NULL; } #endif } #endif /* --- debug settings and utilities --- */ #if ! dbglog_HAVE #define WriteExtraErr(s) #else LOCALPROC WriteExtraErr(char *s) { dbglog_writeCStr("*** error: "); dbglog_writeCStr(s); dbglog_writeReturn(); } #endif LOCALVAR Display *x_display = NULL; #define DbgEvents (dbglog_HAVE && 0) #if DbgEvents LOCALPROC WriteDbgAtom(char *s, Atom x) { char *name = XGetAtomName(x_display, x); if (name != NULL) { dbglog_writeCStr("Atom "); dbglog_writeCStr(s); dbglog_writeCStr(": "); dbglog_writeCStr(name); dbglog_writeReturn(); XFree(name); } } #endif /* --- information about the environment --- */ LOCALVAR Atom XA_DeleteW = (Atom)0; #if EnableDragDrop LOCALVAR Atom XA_UriList = (Atom)0; LOCALVAR Atom XA_DndAware = (Atom)0; LOCALVAR Atom XA_DndEnter = (Atom)0; LOCALVAR Atom XA_DndLeave = (Atom)0; LOCALVAR Atom XA_DndDrop = (Atom)0; LOCALVAR Atom XA_DndPosition = (Atom)0; LOCALVAR Atom XA_DndStatus = (Atom)0; LOCALVAR Atom XA_DndActionCopy = (Atom)0; LOCALVAR Atom XA_DndActionPrivate = (Atom)0; LOCALVAR Atom XA_DndSelection = (Atom)0; LOCALVAR Atom XA_DndFinished = (Atom)0; LOCALVAR Atom XA_MinivMac_DndXchng = (Atom)0; LOCALVAR Atom XA_NetActiveWindow = (Atom)0; LOCALVAR Atom XA_NetSupported = (Atom)0; #endif #if IncludeHostTextClipExchange LOCALVAR Atom XA_CLIPBOARD = (Atom)0; LOCALVAR Atom XA_TARGETS = (Atom)0; LOCALVAR Atom XA_MinivMac_Clip = (Atom)0; #endif LOCALPROC LoadXA(void) { XA_DeleteW = XInternAtom(x_display, "WM_DELETE_WINDOW", False); #if EnableDragDrop XA_UriList = XInternAtom (x_display, "text/uri-list", False); XA_DndAware = XInternAtom (x_display, "XdndAware", False); XA_DndEnter = XInternAtom(x_display, "XdndEnter", False); XA_DndLeave = XInternAtom(x_display, "XdndLeave", False); XA_DndDrop = XInternAtom(x_display, "XdndDrop", False); XA_DndPosition = XInternAtom(x_display, "XdndPosition", False); XA_DndStatus = XInternAtom(x_display, "XdndStatus", False); XA_DndActionCopy = XInternAtom(x_display, "XdndActionCopy", False); XA_DndActionPrivate = XInternAtom(x_display, "XdndActionPrivate", False); XA_DndSelection = XInternAtom(x_display, "XdndSelection", False); XA_DndFinished = XInternAtom(x_display, "XdndFinished", False); XA_MinivMac_DndXchng = XInternAtom(x_display, "_MinivMac_DndXchng", False); XA_NetActiveWindow = XInternAtom(x_display, "_NET_ACTIVE_WINDOW", False); XA_NetSupported = XInternAtom(x_display, "_NET_SUPPORTED", False); #endif #if IncludeHostTextClipExchange XA_CLIPBOARD = XInternAtom(x_display, "CLIPBOARD", False); XA_TARGETS = XInternAtom(x_display, "TARGETS", False); XA_MinivMac_Clip = XInternAtom(x_display, "_MinivMac_Clip", False); #endif } #if EnableDragDrop LOCALFUNC bool NetSupportedContains(Atom x) { /* Note that the window manager could be replaced at any time, so don't cache results of this function. */ Atom ret_type; int ret_format; unsigned long ret_item; unsigned long remain_byte; unsigned long i; unsigned char *s = 0; bool foundit = false; Window rootwin = XRootWindow(x_display, DefaultScreen(x_display)); if (Success != XGetWindowProperty(x_display, rootwin, XA_NetSupported, 0, 65535, False, XA_ATOM, &ret_type, &ret_format, &ret_item, &remain_byte, &s)) { WriteExtraErr("XGetWindowProperty failed"); } else if (! s) { WriteExtraErr("XGetWindowProperty failed"); } else if (ret_type != XA_ATOM) { WriteExtraErr("XGetWindowProperty returns wrong type"); } else { Atom *v = (Atom *)s; for (i = 0; i < ret_item; ++i) { if (v[i] == x) { foundit = true; /* fprintf(stderr, "found the hint\n"); */ } } } if (s) { XFree(s); } return foundit; } #endif #define WantColorTransValid 1 #include "UI/COMOSGLU.h" #include "UTIL/PBUFSTDC.h" #include "UI/CONTROLM.h" /* --- text translation --- */ #if IncludePbufs /* this is table for Windows, any changes needed for X? */ LOCALVAR const uint8_t Native2MacRomanTab[] = { 0xAD, 0xB0, 0xE2, 0xC4, 0xE3, 0xC9, 0xA0, 0xE0, 0xF6, 0xE4, 0xB6, 0xDC, 0xCE, 0xB2, 0xB3, 0xB7, 0xB8, 0xD4, 0xD5, 0xD2, 0xD3, 0xA5, 0xD0, 0xD1, 0xF7, 0xAA, 0xC5, 0xDD, 0xCF, 0xB9, 0xC3, 0xD9, 0xCA, 0xC1, 0xA2, 0xA3, 0xDB, 0xB4, 0xBA, 0xA4, 0xAC, 0xA9, 0xBB, 0xC7, 0xC2, 0xBD, 0xA8, 0xF8, 0xA1, 0xB1, 0xC6, 0xD7, 0xAB, 0xB5, 0xA6, 0xE1, 0xFC, 0xDA, 0xBC, 0xC8, 0xDE, 0xDF, 0xF0, 0xC0, 0xCB, 0xE7, 0xE5, 0xCC, 0x80, 0x81, 0xAE, 0x82, 0xE9, 0x83, 0xE6, 0xE8, 0xED, 0xEA, 0xEB, 0xEC, 0xF5, 0x84, 0xF1, 0xEE, 0xEF, 0xCD, 0x85, 0xF9, 0xAF, 0xF4, 0xF2, 0xF3, 0x86, 0xFA, 0xFB, 0xA7, 0x88, 0x87, 0x89, 0x8B, 0x8A, 0x8C, 0xBE, 0x8D, 0x8F, 0x8E, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, 0xFD, 0x96, 0x98, 0x97, 0x99, 0x9B, 0x9A, 0xD6, 0xBF, 0x9D, 0x9C, 0x9E, 0x9F, 0xFE, 0xFF, 0xD8 }; #endif #if IncludePbufs LOCALFUNC MacErr_t NativeTextToMacRomanPbuf(char *x, tPbuf *r) { if (NULL == x) { return mnvm_miscErr; } else { uint8_t * p; uint32_t L = strlen(x); p = (uint8_t *)malloc(L); if (NULL == p) { return mnvm_miscErr; } else { uint8_t *p0 = (uint8_t *)x; uint8_t *p1 = (uint8_t *)p; int i; for (i = L; --i >= 0; ) { uint8_t v = *p0++; if (v >= 128) { v = Native2MacRomanTab[v - 128]; } else if (10 == v) { v = 13; } *p1++ = v; } return PbufNewFromPtr(p, L, r); } } } #endif #if IncludePbufs /* this is table for Windows, any changes needed for X? */ LOCALVAR const uint8_t MacRoman2NativeTab[] = { 0xC4, 0xC5, 0xC7, 0xC9, 0xD1, 0xD6, 0xDC, 0xE1, 0xE0, 0xE2, 0xE4, 0xE3, 0xE5, 0xE7, 0xE9, 0xE8, 0xEA, 0xEB, 0xED, 0xEC, 0xEE, 0xEF, 0xF1, 0xF3, 0xF2, 0xF4, 0xF6, 0xF5, 0xFA, 0xF9, 0xFB, 0xFC, 0x86, 0xB0, 0xA2, 0xA3, 0xA7, 0x95, 0xB6, 0xDF, 0xAE, 0xA9, 0x99, 0xB4, 0xA8, 0x80, 0xC6, 0xD8, 0x81, 0xB1, 0x8D, 0x8E, 0xA5, 0xB5, 0x8A, 0x8F, 0x90, 0x9D, 0xA6, 0xAA, 0xBA, 0xAD, 0xE6, 0xF8, 0xBF, 0xA1, 0xAC, 0x9E, 0x83, 0x9A, 0xB2, 0xAB, 0xBB, 0x85, 0xA0, 0xC0, 0xC3, 0xD5, 0x8C, 0x9C, 0x96, 0x97, 0x93, 0x94, 0x91, 0x92, 0xF7, 0xB3, 0xFF, 0x9F, 0xB9, 0xA4, 0x8B, 0x9B, 0xBC, 0xBD, 0x87, 0xB7, 0x82, 0x84, 0x89, 0xC2, 0xCA, 0xC1, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0xD3, 0xD4, 0xBE, 0xD2, 0xDA, 0xDB, 0xD9, 0xD0, 0x88, 0x98, 0xAF, 0xD7, 0xDD, 0xDE, 0xB8, 0xF0, 0xFD, 0xFE }; #endif #if IncludePbufs LOCALFUNC bool MacRomanTextToNativePtr(tPbuf i, bool IsFileName, uint8_t * *r) { uint8_t * p; void *Buffer = PbufDat[i]; uint32_t L = PbufSize[i]; p = (uint8_t *)malloc(L + 1); if (p != NULL) { uint8_t *p0 = (uint8_t *)Buffer; uint8_t *p1 = (uint8_t *)p; int j; if (IsFileName) { for (j = L; --j >= 0; ) { uint8_t x = *p0++; if (x < 32) { x = '-'; } else if (x >= 128) { x = MacRoman2NativeTab[x - 128]; } else { switch (x) { case '/': case '<': case '>': case '|': case ':': x = '-'; default: break; } } *p1++ = x; } if ('.' == p[0]) { p[0] = '-'; } } else { for (j = L; --j >= 0; ) { uint8_t x = *p0++; if (x >= 128) { x = MacRoman2NativeTab[x - 128]; } else if (13 == x) { x = '\n'; } *p1++ = x; } } *p1 = 0; *r = p; return true; } return false; } #endif LOCALPROC NativeStrFromCStr(char *r, char *s) { uint8_t ps[ClStrMaxLength]; int i; int L; ClStrFromSubstCStr(&L, ps, s); for (i = 0; i < L; ++i) { r[i] = Cell2PlainAsciiMap[ps[i]]; } r[L] = 0; } /* --- drives --- */ #define NotAfileRef NULL LOCALVAR FILE *Drives[NumDrives]; /* open disk image files */ #if IncludeSonyGetName || IncludeSonyNew LOCALVAR char *DriveNames[NumDrives]; #endif LOCALPROC InitDrives(void) { /* This isn't really needed, Drives[i] and DriveNames[i] need not have valid values when not vSonyIsInserted[i]. */ tDrive i; for (i = 0; i < NumDrives; ++i) { Drives[i] = NotAfileRef; #if IncludeSonyGetName || IncludeSonyNew DriveNames[i] = NULL; #endif } } GLOBALOSGLUFUNC MacErr_t vSonyTransfer(bool IsWrite, uint8_t * Buffer, tDrive Drive_No, uint32_t Sony_Start, uint32_t Sony_Count, uint32_t *Sony_ActCount) { MacErr_t err = mnvm_miscErr; FILE *refnum = Drives[Drive_No]; uint32_t NewSony_Count = 0; if (0 == fseek(refnum, Sony_Start, SEEK_SET)) { if (IsWrite) { NewSony_Count = fwrite(Buffer, 1, Sony_Count, refnum); } else { NewSony_Count = fread(Buffer, 1, Sony_Count, refnum); } if (NewSony_Count == Sony_Count) { err = mnvm_noErr; } } if (nullpr != Sony_ActCount) { *Sony_ActCount = NewSony_Count; } return err; /*& figure out what really to return &*/ } GLOBALOSGLUFUNC MacErr_t vSonyGetSize(tDrive Drive_No, uint32_t *Sony_Count) { MacErr_t err = mnvm_miscErr; FILE *refnum = Drives[Drive_No]; long v; if (0 == fseek(refnum, 0, SEEK_END)) { v = ftell(refnum); if (v >= 0) { *Sony_Count = v; err = mnvm_noErr; } } return err; /*& figure out what really to return &*/ } #ifndef HaveAdvisoryLocks #define HaveAdvisoryLocks 1 #endif /* What is the difference between fcntl(fd, F_SETLK ... and flock(fd ... ? */ #if HaveAdvisoryLocks LOCALFUNC bool LockFile(FILE *refnum) { bool IsOk = false; #if 1 struct flock fl; int fd = fileno(refnum); fl.l_start = 0; /* starting offset */ fl.l_len = 0; /* len = 0 means until end of file */ /* fl.pid_t l_pid; */ /* lock owner, don't need to set */ fl.l_type = F_WRLCK; /* lock type: read/write, etc. */ fl.l_whence = SEEK_SET; /* type of l_start */ if (-1 == fcntl(fd, F_SETLK, &fl)) { MacMsg(kStrImageInUseTitle, kStrImageInUseMessage, false); } else { IsOk = true; } #else int fd = fileno(refnum); if (-1 == flock(fd, LOCK_EX | LOCK_NB)) { MacMsg(kStrImageInUseTitle, kStrImageInUseMessage, false); } else { IsOk = true; } #endif return IsOk; } #endif #if HaveAdvisoryLocks LOCALPROC UnlockFile(FILE *refnum) { #if 1 struct flock fl; int fd = fileno(refnum); fl.l_start = 0; /* starting offset */ fl.l_len = 0; /* len = 0 means until end of file */ /* fl.pid_t l_pid; */ /* lock owner, don't need to set */ fl.l_type = F_UNLCK; /* lock type: read/write, etc. */ fl.l_whence = SEEK_SET; /* type of l_start */ if (-1 == fcntl(fd, F_SETLK, &fl)) { /* an error occurred */ } #else int fd = fileno(refnum); if (-1 == flock(fd, LOCK_UN)) { } #endif } #endif LOCALFUNC MacErr_t vSonyEject0(tDrive Drive_No, bool deleteit) { FILE *refnum = Drives[Drive_No]; DiskEjectedNotify(Drive_No); #if HaveAdvisoryLocks UnlockFile(refnum); #endif fclose(refnum); Drives[Drive_No] = NotAfileRef; /* not really needed */ #if IncludeSonyGetName || IncludeSonyNew { char *s = DriveNames[Drive_No]; if (NULL != s) { if (deleteit) { remove(s); } free(s); DriveNames[Drive_No] = NULL; /* not really needed */ } } #endif return mnvm_noErr; } GLOBALOSGLUFUNC MacErr_t vSonyEject(tDrive Drive_No) { return vSonyEject0(Drive_No, false); } #if IncludeSonyNew GLOBALOSGLUFUNC MacErr_t vSonyEjectDelete(tDrive Drive_No) { return vSonyEject0(Drive_No, true); } #endif LOCALPROC UnInitDrives(void) { tDrive i; for (i = 0; i < NumDrives; ++i) { if (vSonyIsInserted(i)) { (void) vSonyEject(i); } } } #if IncludeSonyGetName GLOBALOSGLUFUNC MacErr_t vSonyGetName(tDrive Drive_No, tPbuf *r) { char *drivepath = DriveNames[Drive_No]; if (NULL == drivepath) { return mnvm_miscErr; } else { char *s = strrchr(drivepath, '/'); if (NULL == s) { s = drivepath; } else { ++s; } return NativeTextToMacRomanPbuf(s, r); } } #endif LOCALFUNC bool Sony_Insert0(FILE *refnum, bool locked, char *drivepath) { tDrive Drive_No; bool IsOk = false; if (! FirstFreeDisk(&Drive_No)) { MacMsg(kStrTooManyImagesTitle, kStrTooManyImagesMessage, false); } else { /* printf("Sony_Insert0 %d\n", (int)Drive_No); */ #if HaveAdvisoryLocks if (locked || LockFile(refnum)) #endif { Drives[Drive_No] = refnum; DiskInsertNotify(Drive_No, locked); #if IncludeSonyGetName || IncludeSonyNew { uint32_t L = strlen(drivepath); char *p = malloc(L + 1); if (p != NULL) { (void) memcpy(p, drivepath, L + 1); } DriveNames[Drive_No] = p; } #endif IsOk = true; } } if (! IsOk) { fclose(refnum); } return IsOk; } LOCALFUNC bool Sony_Insert1(char *drivepath, bool silentfail) { bool locked = false; /* printf("Sony_Insert1 %s\n", drivepath); */ FILE *refnum = fopen(drivepath, "rb+"); if (NULL == refnum) { locked = true; refnum = fopen(drivepath, "rb"); } if (NULL == refnum) { if (! silentfail) { MacMsg(kStrOpenFailTitle, kStrOpenFailMessage, false); } } else { return Sony_Insert0(refnum, locked, drivepath); } return false; } LOCALFUNC MacErr_t LoadMacRomFrom(char *path) { MacErr_t err; FILE *ROM_File; int File_Size; ROM_File = fopen(path, "rb"); if (NULL == ROM_File) { err = mnvm_fnfErr; } else { File_Size = fread(ROM, 1, kROM_Size, ROM_File); if (kROM_Size != File_Size) { if (feof(ROM_File)) { MacMsgOverride(kStrShortROMTitle, kStrShortROMMessage); err = mnvm_eofErr; } else { MacMsgOverride(kStrNoReadROMTitle, kStrNoReadROMMessage); err = mnvm_miscErr; } } else { err = ROM_IsValid(); } fclose(ROM_File); } return err; } LOCALFUNC bool Sony_Insert1a(char *drivepath, bool silentfail) { bool v; if (! ROM_loaded) { v = (mnvm_noErr == LoadMacRomFrom(drivepath)); } else { v = Sony_Insert1(drivepath, silentfail); } return v; } LOCALFUNC bool Sony_Insert2(char *s) { char *d = #ifdef CanGetAppPath (NULL == d_arg) ? app_parent : #endif d_arg; bool IsOk = false; if (NULL == d) { IsOk = Sony_Insert1(s, true); } else { char *t; if (mnvm_noErr == ChildPath(d, s, &t)) { IsOk = Sony_Insert1(t, true); free(t); } } return IsOk; } LOCALFUNC bool Sony_InsertIth(int i) { bool v; if ((i > 9) || ! FirstFreeDisk(nullpr)) { v = false; } else { char s[] = "disk?.dsk"; s[4] = '0' + i; v = Sony_Insert2(s); } return v; } LOCALFUNC bool LoadInitialImages(void) { if (! AnyDiskInserted()) { int i; for (i = 1; Sony_InsertIth(i); ++i) { /* stop on first error (including file not found) */ } } return true; } #if IncludeSonyNew LOCALFUNC bool WriteZero(FILE *refnum, uint32_t L) { #define ZeroBufferSize 2048 uint32_t i; uint8_t buffer[ZeroBufferSize]; memset(&buffer, 0, ZeroBufferSize); while (L > 0) { i = (L > ZeroBufferSize) ? ZeroBufferSize : L; if (fwrite(buffer, 1, i, refnum) != i) { return false; } L -= i; } return true; } #endif #if IncludeSonyNew LOCALPROC MakeNewDisk0(uint32_t L, char *drivepath) { bool IsOk = false; FILE *refnum = fopen(drivepath, "wb+"); if (NULL == refnum) { MacMsg(kStrOpenFailTitle, kStrOpenFailMessage, false); } else { if (WriteZero(refnum, L)) { IsOk = Sony_Insert0(refnum, false, drivepath); refnum = NULL; } if (refnum != NULL) { fclose(refnum); } if (! IsOk) { (void) remove(drivepath); } } } #endif #if IncludeSonyNew LOCALPROC MakeNewDisk(uint32_t L, char *drivename) { char *d = #ifdef CanGetAppPath (NULL == d_arg) ? app_parent : #endif d_arg; if (NULL == d) { MakeNewDisk0(L, drivename); /* in current directory */ } else { MacErr_t err; char *t = NULL; char *t2 = NULL; if (mnvm_noErr == (err = FindOrMakeChild(d, "out", &t))) if (mnvm_noErr == (err = ChildPath(t, drivename, &t2))) { MakeNewDisk0(L, t2); } MayFree(t2); MayFree(t); } } #endif #if IncludeSonyNew LOCALPROC MakeNewDiskAtDefault(uint32_t L) { char s[ClStrMaxLength + 1]; NativeStrFromCStr(s, "untitled.dsk"); MakeNewDisk(L, s); } #endif /* --- ROM --- */ LOCALVAR char *rom_path = NULL; #if 0 #include #include #endif LOCALFUNC MacErr_t FindUserHomeFolder(char **r) { MacErr_t err; char *s; #if 0 struct passwd *user; #endif if (NULL != (s = getenv("HOME"))) { *r = s; err = mnvm_noErr; } else #if 0 if ((NULL != (user = getpwuid(getuid()))) && (NULL != (s = user->pw_dir))) { /* From getpwuid man page: "An application that wants to determine its user's home directory should inspect the value of HOME (rather than the value getpwuid(getuid())->pw_dir) since this allows the user to modify their notion of "the home directory" during a login session." But it is possible for HOME to not be set. Some sources say to use getpwuid in that case. */ *r = s; err = mnvm_noErr; } else #endif { err = mnvm_fnfErr; } return err; } LOCALFUNC MacErr_t LoadMacRomFromHome(void) { MacErr_t err; char *s; char *t = NULL; char *t2 = NULL; char *t3 = NULL; if (mnvm_noErr == (err = FindUserHomeFolder(&s))) if (mnvm_noErr == (err = ChildPath(s, ".gryphel", &t))) if (mnvm_noErr == (err = ChildPath(t, "mnvm_rom", &t2))) if (mnvm_noErr == (err = ChildPath(t2, RomFileName, &t3))) { err = LoadMacRomFrom(t3); } MayFree(t3); MayFree(t2); MayFree(t); return err; } #ifdef CanGetAppPath LOCALFUNC MacErr_t LoadMacRomFromAppPar(void) { MacErr_t err; char *d = #ifdef CanGetAppPath (NULL == d_arg) ? app_parent : #endif d_arg; char *t = NULL; if (NULL == d) { err = mnvm_fnfErr; } else { if (mnvm_noErr == (err = ChildPath(d, RomFileName, &t))) { err = LoadMacRomFrom(t); } } MayFree(t); return err; } #endif LOCALFUNC bool LoadMacRom(void) { MacErr_t err; if ((NULL == rom_path) || (mnvm_fnfErr == (err = LoadMacRomFrom(rom_path)))) #ifdef CanGetAppPath if (mnvm_fnfErr == (err = LoadMacRomFromAppPar())) #endif if (mnvm_fnfErr == (err = LoadMacRomFromHome())) if (mnvm_fnfErr == (err = LoadMacRomFrom(RomFileName))) { } return true; /* keep launching Mini vMac, regardless */ } /* --- video out --- */ LOCALVAR Window main_wind = 0; LOCALVAR GC gc = NULL; LOCALVAR bool NeedFinishOpen1 = false; LOCALVAR bool NeedFinishOpen2 = false; LOCALVAR XColor x_black; LOCALVAR XColor x_white; #if MayFullScreen LOCALVAR short hOffset; LOCALVAR short vOffset; #endif #if 1 LOCALVAR bool UseFullScreen = (WantInitFullScreen != 0); #endif #if 1 LOCALVAR bool UseMagnify = (WantInitMagnify != 0); #endif LOCALVAR bool gBackgroundFlag = false; LOCALVAR bool gTrueBackgroundFlag = false; LOCALVAR bool CurSpeedStopped = true; #ifndef UseColorImage #define UseColorImage (0 != vMacScreenDepth) #endif LOCALVAR XImage *image = NULL; #if 1 LOCALVAR XImage *Scaled_image = NULL; #endif #if 1 #define MaxScale WindowScale #else #define MaxScale 1 #endif #define WantScalingTabl (1 || UseColorImage) #if WantScalingTabl LOCALVAR uint8_t * ScalingTabl = nullpr; #define ScalingTablsz1 (256 * MaxScale) #if UseColorImage #define ScalingTablsz (ScalingTablsz1 << 5) #else #define ScalingTablsz ScalingTablsz1 #endif #endif /* WantScalingTabl */ #define WantScalingBuff (1 || UseColorImage) #if WantScalingBuff LOCALVAR uint8_t * ScalingBuff = nullpr; #if UseColorImage #define ScalingBuffsz \ (vMacScreenNumPixels * 4 * MaxScale * MaxScale) #else #define ScalingBuffsz ((long)vMacScreenMonoNumBytes \ * MaxScale * MaxScale) #endif #endif /* WantScalingBuff */ #if 1 && ! UseColorImage LOCALPROC SetUpScalingTabl(void) { uint8_t *p4; int i; int j; int k; uint8_t bitsRemaining; uint8_t t1; uint8_t t2; p4 = ScalingTabl; for (i = 0; i < 256; ++i) { bitsRemaining = 8; t2 = 0; for (j = 8; --j >= 0; ) { t1 = (i >> j) & 1; for (k = WindowScale; --k >= 0; ) { t2 = (t2 << 1) | t1; if (--bitsRemaining == 0) { *p4++ = t2; bitsRemaining = 8; t2 = 0; } } } } } #endif //#if 1 && (0 != vMacScreenDepth) && (vMacScreenDepth < 4) LOCALPROC SetUpColorScalingTabl(void) { int i; int j; int k; int a; uint32_t v; uint32_t * p4; p4 = (uint32_t *)ScalingTabl; for (i = 0; i < 256; ++i) { for (k = 1 << (3 - vMacScreenDepth); --k >= 0; ) { j = (i >> (k << vMacScreenDepth)) & (CLUT_size - 1); v = (((long)CLUT_reds[j] & 0xFF00) << 8) | ((long)CLUT_greens[j] & 0xFF00) | (((long)CLUT_blues[j] & 0xFF00) >> 8); for (a = WindowScale; --a >= 0; ) { *p4++ = v; } } } } //#if (0 != vMacScreenDepth) && (vMacScreenDepth < 4) LOCALPROC SetUpColorTabl(void) { int i; int j; int k; uint32_t * p4; p4 = (uint32_t *)ScalingTabl; for (i = 0; i < 256; ++i) { for (k = 1 << (3 - vMacScreenDepth); --k >= 0; ) { j = (i >> (k << vMacScreenDepth)) & (CLUT_size - 1); *p4++ = (((long)CLUT_reds[j] & 0xFF00) << 8) | ((long)CLUT_greens[j] & 0xFF00) | (((long)CLUT_blues[j] & 0xFF00) >> 8); } } } //#if 1 && UseColorImage LOCALPROC SetUpBW2ColorScalingTabl(void) { int i; int k; int a; uint32_t v; uint32_t * p4; p4 = (uint32_t *)ScalingTabl; for (i = 0; i < 256; ++i) { for (k = 8; --k >= 0; ) { if (0 != ((i >> k) & 1)) { v = 0; } else { v = 0xFFFFFF; } for (a = WindowScale; --a >= 0; ) { *p4++ = v; } } } } //#if UseColorImage LOCALPROC SetUpBW2ColorTabl(void) { int i; int k; uint32_t v; uint32_t * p4; p4 = (uint32_t *)ScalingTabl; for (i = 0; i < 256; ++i) { for (k = 8; --k >= 0; ) { if (0 != ((i >> k) & 1)) { v = 0; } else { v = 0xFFFFFF; } *p4++ = v; } } } #if 1 && ! UseColorImage #define ScrnMapr_DoMap UpdateScaledBWCopy #define ScrnMapr_Src GetCurDrawBuff() #define ScrnMapr_Dst ScalingBuff #define ScrnMapr_SrcDepth 0 #define ScrnMapr_DstDepth 0 #define ScrnMapr_Map ScalingTabl #define ScrnMapr_Scale WindowScale #include "HW/SCREEN/SCRNMAPR.h" #endif #if (0 != vMacScreenDepth) && (vMacScreenDepth < 4) #define ScrnMapr_DoMap UpdateMappedColorCopy #define ScrnMapr_Src GetCurDrawBuff() #define ScrnMapr_Dst ScalingBuff #define ScrnMapr_SrcDepth vMacScreenDepth #define ScrnMapr_DstDepth 5 #define ScrnMapr_Map ScalingTabl #include "HW/SCREEN/SCRNMAPR.h" #endif #if 1 && (0 != vMacScreenDepth) && (vMacScreenDepth < 4) #define ScrnMapr_DoMap UpdateMappedScaledColorCopy #define ScrnMapr_Src GetCurDrawBuff() #define ScrnMapr_Dst ScalingBuff #define ScrnMapr_SrcDepth vMacScreenDepth #define ScrnMapr_DstDepth 5 #define ScrnMapr_Map ScalingTabl #define ScrnMapr_Scale WindowScale #include "HW/SCREEN/SCRNMAPR.h" #endif #if vMacScreenDepth >= 4 #define ScrnTrns_DoTrans UpdateTransColorCopy #define ScrnTrns_Src GetCurDrawBuff() #define ScrnTrns_Dst ScalingBuff #define ScrnTrns_SrcDepth vMacScreenDepth #define ScrnTrns_DstDepth 5 #include "HW/SCREEN/SCRNTRNS.h" #endif #if 1 && (vMacScreenDepth >= 4) #define ScrnTrns_DoTrans UpdateTransScaledColorCopy #define ScrnTrns_Src GetCurDrawBuff() #define ScrnTrns_Dst ScalingBuff #define ScrnTrns_SrcDepth vMacScreenDepth #define ScrnTrns_DstDepth 5 #define ScrnTrns_Scale WindowScale #include "HW/SCREEN/SCRNTRNS.h" #endif #if 1 && UseColorImage #define ScrnMapr_DoMap UpdateMappedScaledBW2ColorCopy #define ScrnMapr_Src GetCurDrawBuff() #define ScrnMapr_Dst ScalingBuff #define ScrnMapr_SrcDepth 0 #define ScrnMapr_DstDepth 5 #define ScrnMapr_Map ScalingTabl #define ScrnMapr_Scale WindowScale #include "HW/SCREEN/SCRNMAPR.h" #endif #if UseColorImage #define ScrnMapr_DoMap UpdateMappedBW2ColorCopy #define ScrnMapr_Src GetCurDrawBuff() #define ScrnMapr_Dst ScalingBuff #define ScrnMapr_SrcDepth 0 #define ScrnMapr_DstDepth 5 #define ScrnMapr_Map ScalingTabl #include "HW/SCREEN/SCRNMAPR.h" #endif LOCALPROC HaveChangedScreenBuff(uint16_t top, uint16_t left, uint16_t bottom, uint16_t right) { int XDest; int YDest; char *the_data; #if 1 if (UseFullScreen) #endif #if MayFullScreen { if (top < ViewVStart) { top = ViewVStart; } if (left < ViewHStart) { left = ViewHStart; } if (bottom > ViewVStart + ViewVSize) { bottom = ViewVStart + ViewVSize; } if (right > ViewHStart + ViewHSize) { right = ViewHStart + ViewHSize; } if ((top >= bottom) || (left >= right)) { goto label_exit; } } #endif XDest = left; YDest = top; #if 1 if (UseFullScreen) #endif #if MayFullScreen { XDest -= ViewHStart; YDest -= ViewVStart; } #endif #if 1 if (UseMagnify) { XDest *= WindowScale; YDest *= WindowScale; } #endif #if 1 if (UseFullScreen) #endif #if MayFullScreen { XDest += hOffset; YDest += vOffset; } #endif #if 1 if (UseMagnify) { #if UseColorImage #if 0 != vMacScreenDepth if (UseColorMode) { #if vMacScreenDepth < 4 if (! ColorTransValid) { SetUpColorScalingTabl(); ColorTransValid = true; } UpdateMappedScaledColorCopy(top, left, bottom, right); #else UpdateTransScaledColorCopy(top, left, bottom, right); #endif } else #endif /* 0 != vMacScreenDepth */ { if (! ColorTransValid) { SetUpBW2ColorScalingTabl(); ColorTransValid = true; } UpdateMappedScaledBW2ColorCopy(top, left, bottom, right); } #else /* ! UseColorImage */ /* assume 0 == vMacScreenDepth */ { if (! ColorTransValid) { SetUpScalingTabl(); ColorTransValid = true; } UpdateScaledBWCopy(top, left, bottom, right); } #endif /* UseColorImage */ { char *saveData = Scaled_image->data; Scaled_image->data = (char *)ScalingBuff; XPutImage(x_display, main_wind, gc, Scaled_image, left * WindowScale, top * WindowScale, XDest, YDest, (right - left) * WindowScale, (bottom - top) * WindowScale); Scaled_image->data = saveData; } } else #endif /* 1 */ { #if UseColorImage #if 0 != vMacScreenDepth if (UseColorMode) { #if vMacScreenDepth < 4 if (! ColorTransValid) { SetUpColorTabl(); ColorTransValid = true; } UpdateMappedColorCopy(top, left, bottom, right); the_data = (char *)ScalingBuff; #else /* if vMacScreenDepth == 5 and MSBFirst, could copy directly with the_data = (char *)GetCurDrawBuff(); */ UpdateTransColorCopy(top, left, bottom, right); the_data = (char *)ScalingBuff; #endif } else #endif /* 0 != vMacScreenDepth */ { if (! ColorTransValid) { SetUpBW2ColorTabl(); ColorTransValid = true; } UpdateMappedBW2ColorCopy(top, left, bottom, right); the_data = (char *)ScalingBuff; } #else /* ! UseColorImage */ { the_data = (char *)GetCurDrawBuff(); } #endif /* UseColorImage */ { char *saveData = image->data; image->data = the_data; XPutImage(x_display, main_wind, gc, image, left, top, XDest, YDest, right - left, bottom - top); image->data = saveData; } } #if MayFullScreen label_exit: ; #endif } LOCALPROC DrawChangesAndClear(void) { if (ScreenChangedBottom > ScreenChangedTop) { HaveChangedScreenBuff(ScreenChangedTop, ScreenChangedLeft, ScreenChangedBottom, ScreenChangedRight); ScreenClearChanges(); } } /* --- mouse --- */ /* cursor hiding */ LOCALVAR bool HaveCursorHidden = false; LOCALVAR bool WantCursorHidden = false; LOCALPROC ForceShowCursor(void) { if (HaveCursorHidden) { HaveCursorHidden = false; if (main_wind) { XUndefineCursor(x_display, main_wind); } } } LOCALVAR Cursor blankCursor = None; LOCALFUNC bool CreateBlankCursor(Window rootwin) /* adapted from X11_CreateNullCursor in context.x11.c in quakeforge 0.5.5, copyright Id Software, Inc. Zephaniah E. Hull, and Jeff Teunissen. */ { Pixmap cursormask; XGCValues xgc; GC gc; bool IsOk = false; cursormask = XCreatePixmap(x_display, rootwin, 1, 1, 1); if (None == cursormask) { WriteExtraErr("XCreatePixmap failed."); } else { xgc.function = GXclear; gc = XCreateGC(x_display, cursormask, GCFunction, &xgc); if (None == gc) { WriteExtraErr("XCreateGC failed."); } else { XFillRectangle(x_display, cursormask, gc, 0, 0, 1, 1); XFreeGC(x_display, gc); blankCursor = XCreatePixmapCursor(x_display, cursormask, cursormask, &x_black, &x_white, 0, 0); if (None == blankCursor) { WriteExtraErr("XCreatePixmapCursor failed."); } else { IsOk = true; } } XFreePixmap(x_display, cursormask); /* assuming that XCreatePixmapCursor doesn't think it owns the pixmaps passed to it. I've seen code that assumes this, and other code that seems to assume the opposite. */ } return IsOk; } /* cursor moving */ #if EnableMoveMouse LOCALFUNC bool MoveMouse(int16_t h, int16_t v) { int NewMousePosh; int NewMousePosv; int root_x_return; int root_y_return; Window root_return; Window child_return; unsigned int mask_return; bool IsOk; int attempts = 0; #if 1 if (UseFullScreen) #endif #if MayFullScreen { h -= ViewHStart; v -= ViewVStart; } #endif #if 1 if (UseMagnify) { h *= WindowScale; v *= WindowScale; } #endif #if 1 if (UseFullScreen) #endif #if MayFullScreen { h += hOffset; v += vOffset; } #endif do { XWarpPointer(x_display, None, main_wind, 0, 0, 0, 0, h, v); XQueryPointer(x_display, main_wind, &root_return, &child_return, &root_x_return, &root_y_return, &NewMousePosh, &NewMousePosv, &mask_return); IsOk = (h == NewMousePosh) && (v == NewMousePosv); ++attempts; } while ((! IsOk) && (attempts < 10)); return IsOk; } #endif #if EnableFSMouseMotion LOCALPROC StartSaveMouseMotion(void) { if (! HaveMouseMotion) { if (MoveMouse(ViewHStart + (ViewHSize / 2), ViewVStart + (ViewVSize / 2))) { SavedMouseH = ViewHStart + (ViewHSize / 2); SavedMouseV = ViewVStart + (ViewVSize / 2); HaveMouseMotion = true; } } } #endif #if EnableFSMouseMotion LOCALPROC StopSaveMouseMotion(void) { if (HaveMouseMotion) { (void) MoveMouse(CurMouseH, CurMouseV); HaveMouseMotion = false; } } #endif /* cursor state */ #if EnableFSMouseMotion LOCALPROC MouseConstrain(void) { int16_t shiftdh; int16_t shiftdv; if (SavedMouseH < ViewHStart + (ViewHSize / 4)) { shiftdh = ViewHSize / 2; } else if (SavedMouseH > ViewHStart + ViewHSize - (ViewHSize / 4)) { shiftdh = - ViewHSize / 2; } else { shiftdh = 0; } if (SavedMouseV < ViewVStart + (ViewVSize / 4)) { shiftdv = ViewVSize / 2; } else if (SavedMouseV > ViewVStart + ViewVSize - (ViewVSize / 4)) { shiftdv = - ViewVSize / 2; } else { shiftdv = 0; } if ((shiftdh != 0) || (shiftdv != 0)) { SavedMouseH += shiftdh; SavedMouseV += shiftdv; if (! MoveMouse(SavedMouseH, SavedMouseV)) { HaveMouseMotion = false; } } } #endif LOCALPROC MousePositionNotify(int NewMousePosh, int NewMousePosv) { bool ShouldHaveCursorHidden = true; #if 1 if (UseFullScreen) #endif #if MayFullScreen { NewMousePosh -= hOffset; NewMousePosv -= vOffset; } #endif #if 1 if (UseMagnify) { NewMousePosh /= WindowScale; NewMousePosv /= WindowScale; } #endif #if 1 if (UseFullScreen) #endif #if MayFullScreen { NewMousePosh += ViewHStart; NewMousePosv += ViewVStart; } #endif #if EnableFSMouseMotion if (HaveMouseMotion) { MousePositionSetDelta(NewMousePosh - SavedMouseH, NewMousePosv - SavedMouseV); SavedMouseH = NewMousePosh; SavedMouseV = NewMousePosv; } else #endif { if (NewMousePosh < 0) { NewMousePosh = 0; ShouldHaveCursorHidden = false; } else if (NewMousePosh >= vMacScreenWidth) { NewMousePosh = vMacScreenWidth - 1; ShouldHaveCursorHidden = false; } if (NewMousePosv < 0) { NewMousePosv = 0; ShouldHaveCursorHidden = false; } else if (NewMousePosv >= vMacScreenHeight) { NewMousePosv = vMacScreenHeight - 1; ShouldHaveCursorHidden = false; } #if 1 if (UseFullScreen) #endif #if MayFullScreen { ShouldHaveCursorHidden = true; } #endif /* if (ShouldHaveCursorHidden || CurMouseButton) */ /* for a game like arkanoid, would like mouse to still move even when outside window in one direction */ MousePositionSet(NewMousePosh, NewMousePosv); } WantCursorHidden = ShouldHaveCursorHidden; } LOCALPROC CheckMouseState(void) { int NewMousePosh; int NewMousePosv; int root_x_return; int root_y_return; Window root_return; Window child_return; unsigned int mask_return; XQueryPointer(x_display, main_wind, &root_return, &child_return, &root_x_return, &root_y_return, &NewMousePosh, &NewMousePosv, &mask_return); MousePositionNotify(NewMousePosh, NewMousePosv); } /* --- keyboard input --- */ LOCALVAR KeyCode TheCapsLockCode; LOCALVAR uint8_t KC2MKC[256]; LOCALPROC KC2MKCAssignOne(KeySym ks, uint8_t key) { KeyCode code = XKeysymToKeycode(x_display, ks); if (code != NoSymbol) { KC2MKC[code] = key; } #if 0 fprintf(stderr, "%d %d %d\n", (int)ks, key, (int)code); #endif } LOCALFUNC bool KC2MKCInit(void) { int i; for (i = 0; i < 256; ++i) { KC2MKC[i] = MKC_None; } #if 0 /* find Keysym for a code */ for (i = 0; i < 64 * 1024; ++i) { KeyCode code = XKeysymToKeycode(x_display, i); if (115 == code) { fprintf(stderr, "i %d\n", i); } } #endif /* start with redundant mappings, should get overwritten by main mappings but define them just in case */ #ifdef XK_KP_Insert KC2MKCAssignOne(XK_KP_Insert, MKC_KP0); #endif #ifdef XK_KP_End KC2MKCAssignOne(XK_KP_End, MKC_KP1); #endif #ifdef XK_KP_Down KC2MKCAssignOne(XK_KP_Down, MKC_KP2); #endif #ifdef XK_KP_Next KC2MKCAssignOne(XK_KP_Next, MKC_KP3); #endif #ifdef XK_KP_Left KC2MKCAssignOne(XK_KP_Left, MKC_KP4); #endif #ifdef XK_KP_Begin KC2MKCAssignOne(XK_KP_Begin, MKC_KP5); #endif #ifdef XK_KP_Right KC2MKCAssignOne(XK_KP_Right, MKC_KP6); #endif #ifdef XK_KP_Home KC2MKCAssignOne(XK_KP_Home, MKC_KP7); #endif #ifdef XK_KP_Up KC2MKCAssignOne(XK_KP_Up, MKC_KP8); #endif #ifdef XK_KP_Prior KC2MKCAssignOne(XK_KP_Prior, MKC_KP9); #endif #ifdef XK_KP_Delete KC2MKCAssignOne(XK_KP_Delete, MKC_Decimal); #endif KC2MKCAssignOne(XK_asciitilde, MKC_formac_Grave); KC2MKCAssignOne(XK_underscore, MKC_Minus); KC2MKCAssignOne(XK_plus, MKC_Equal); KC2MKCAssignOne(XK_braceleft, MKC_LeftBracket); KC2MKCAssignOne(XK_braceright, MKC_RightBracket); KC2MKCAssignOne(XK_bar, MKC_formac_BackSlash); KC2MKCAssignOne(XK_colon, MKC_SemiColon); KC2MKCAssignOne(XK_quotedbl, MKC_SingleQuote); KC2MKCAssignOne(XK_less, MKC_Comma); KC2MKCAssignOne(XK_greater, MKC_Period); KC2MKCAssignOne(XK_question, MKC_formac_Slash); KC2MKCAssignOne(XK_a, MKC_A); KC2MKCAssignOne(XK_b, MKC_B); KC2MKCAssignOne(XK_c, MKC_C); KC2MKCAssignOne(XK_d, MKC_D); KC2MKCAssignOne(XK_e, MKC_E); KC2MKCAssignOne(XK_f, MKC_F); KC2MKCAssignOne(XK_g, MKC_G); KC2MKCAssignOne(XK_h, MKC_H); KC2MKCAssignOne(XK_i, MKC_I); KC2MKCAssignOne(XK_j, MKC_J); KC2MKCAssignOne(XK_k, MKC_K); KC2MKCAssignOne(XK_l, MKC_L); KC2MKCAssignOne(XK_m, MKC_M); KC2MKCAssignOne(XK_n, MKC_N); KC2MKCAssignOne(XK_o, MKC_O); KC2MKCAssignOne(XK_p, MKC_P); KC2MKCAssignOne(XK_q, MKC_Q); KC2MKCAssignOne(XK_r, MKC_R); KC2MKCAssignOne(XK_s, MKC_S); KC2MKCAssignOne(XK_t, MKC_T); KC2MKCAssignOne(XK_u, MKC_U); KC2MKCAssignOne(XK_v, MKC_V); KC2MKCAssignOne(XK_w, MKC_W); KC2MKCAssignOne(XK_x, MKC_X); KC2MKCAssignOne(XK_y, MKC_Y); KC2MKCAssignOne(XK_z, MKC_Z); /* main mappings */ KC2MKCAssignOne(XK_F1, MKC_formac_F1); KC2MKCAssignOne(XK_F2, MKC_formac_F2); KC2MKCAssignOne(XK_F3, MKC_formac_F3); KC2MKCAssignOne(XK_F4, MKC_formac_F4); KC2MKCAssignOne(XK_F5, MKC_formac_F5); KC2MKCAssignOne(XK_F6, MKC_F6); KC2MKCAssignOne(XK_F7, MKC_F7); KC2MKCAssignOne(XK_F8, MKC_F8); KC2MKCAssignOne(XK_F9, MKC_F9); KC2MKCAssignOne(XK_F10, MKC_F10); KC2MKCAssignOne(XK_F11, MKC_F11); KC2MKCAssignOne(XK_F12, MKC_F12); #ifdef XK_Delete KC2MKCAssignOne(XK_Delete, MKC_formac_ForwardDel); #endif #ifdef XK_Insert KC2MKCAssignOne(XK_Insert, MKC_formac_Help); #endif #ifdef XK_Help KC2MKCAssignOne(XK_Help, MKC_formac_Help); #endif #ifdef XK_Home KC2MKCAssignOne(XK_Home, MKC_formac_Home); #endif #ifdef XK_End KC2MKCAssignOne(XK_End, MKC_formac_End); #endif #ifdef XK_Page_Up KC2MKCAssignOne(XK_Page_Up, MKC_formac_PageUp); #else #ifdef XK_Prior KC2MKCAssignOne(XK_Prior, MKC_formac_PageUp); #endif #endif #ifdef XK_Page_Down KC2MKCAssignOne(XK_Page_Down, MKC_formac_PageDown); #else #ifdef XK_Next KC2MKCAssignOne(XK_Next, MKC_formac_PageDown); #endif #endif #ifdef XK_Print KC2MKCAssignOne(XK_Print, MKC_Print); #endif #ifdef XK_Scroll_Lock KC2MKCAssignOne(XK_Scroll_Lock, MKC_ScrollLock); #endif #ifdef XK_Pause KC2MKCAssignOne(XK_Pause, MKC_Pause); #endif KC2MKCAssignOne(XK_KP_Add, MKC_KPAdd); KC2MKCAssignOne(XK_KP_Subtract, MKC_KPSubtract); KC2MKCAssignOne(XK_KP_Multiply, MKC_KPMultiply); KC2MKCAssignOne(XK_KP_Divide, MKC_KPDevide); KC2MKCAssignOne(XK_KP_Enter, MKC_formac_Enter); KC2MKCAssignOne(XK_KP_Equal, MKC_KPEqual); KC2MKCAssignOne(XK_KP_0, MKC_KP0); KC2MKCAssignOne(XK_KP_1, MKC_KP1); KC2MKCAssignOne(XK_KP_2, MKC_KP2); KC2MKCAssignOne(XK_KP_3, MKC_KP3); KC2MKCAssignOne(XK_KP_4, MKC_KP4); KC2MKCAssignOne(XK_KP_5, MKC_KP5); KC2MKCAssignOne(XK_KP_6, MKC_KP6); KC2MKCAssignOne(XK_KP_7, MKC_KP7); KC2MKCAssignOne(XK_KP_8, MKC_KP8); KC2MKCAssignOne(XK_KP_9, MKC_KP9); KC2MKCAssignOne(XK_KP_Decimal, MKC_Decimal); KC2MKCAssignOne(XK_Left, MKC_Left); KC2MKCAssignOne(XK_Right, MKC_Right); KC2MKCAssignOne(XK_Up, MKC_Up); KC2MKCAssignOne(XK_Down, MKC_Down); KC2MKCAssignOne(XK_grave, MKC_formac_Grave); KC2MKCAssignOne(XK_minus, MKC_Minus); KC2MKCAssignOne(XK_equal, MKC_Equal); KC2MKCAssignOne(XK_bracketleft, MKC_LeftBracket); KC2MKCAssignOne(XK_bracketright, MKC_RightBracket); KC2MKCAssignOne(XK_backslash, MKC_formac_BackSlash); KC2MKCAssignOne(XK_semicolon, MKC_SemiColon); KC2MKCAssignOne(XK_apostrophe, MKC_SingleQuote); KC2MKCAssignOne(XK_comma, MKC_Comma); KC2MKCAssignOne(XK_period, MKC_Period); KC2MKCAssignOne(XK_slash, MKC_formac_Slash); KC2MKCAssignOne(XK_Escape, MKC_formac_Escape); KC2MKCAssignOne(XK_Tab, MKC_Tab); KC2MKCAssignOne(XK_Return, MKC_Return); KC2MKCAssignOne(XK_space, MKC_Space); KC2MKCAssignOne(XK_BackSpace, MKC_BackSpace); KC2MKCAssignOne(XK_Caps_Lock, MKC_formac_CapsLock); KC2MKCAssignOne(XK_Num_Lock, MKC_Clear); KC2MKCAssignOne(XK_Meta_L, MKC_formac_Command); KC2MKCAssignOne(XK_Meta_R, MKC_formac_RCommand); KC2MKCAssignOne(XK_Mode_switch, MKC_formac_Option); KC2MKCAssignOne(XK_Menu, MKC_formac_Option); KC2MKCAssignOne(XK_Super_L, MKC_formac_Option); KC2MKCAssignOne(XK_Super_R, MKC_formac_ROption); KC2MKCAssignOne(XK_Hyper_L, MKC_formac_Option); KC2MKCAssignOne(XK_Hyper_R, MKC_formac_ROption); KC2MKCAssignOne(XK_F13, MKC_formac_Option); /* seen being used in Mandrake Linux 9.2 for windows key */ KC2MKCAssignOne(XK_Shift_L, MKC_formac_Shift); KC2MKCAssignOne(XK_Shift_R, MKC_formac_RShift); KC2MKCAssignOne(XK_Alt_L, MKC_formac_Command); KC2MKCAssignOne(XK_Alt_R, MKC_formac_RCommand); KC2MKCAssignOne(XK_Control_L, MKC_formac_Control); KC2MKCAssignOne(XK_Control_R, MKC_formac_RControl); KC2MKCAssignOne(XK_1, MKC_1); KC2MKCAssignOne(XK_2, MKC_2); KC2MKCAssignOne(XK_3, MKC_3); KC2MKCAssignOne(XK_4, MKC_4); KC2MKCAssignOne(XK_5, MKC_5); KC2MKCAssignOne(XK_6, MKC_6); KC2MKCAssignOne(XK_7, MKC_7); KC2MKCAssignOne(XK_8, MKC_8); KC2MKCAssignOne(XK_9, MKC_9); KC2MKCAssignOne(XK_0, MKC_0); KC2MKCAssignOne(XK_A, MKC_A); KC2MKCAssignOne(XK_B, MKC_B); KC2MKCAssignOne(XK_C, MKC_C); KC2MKCAssignOne(XK_D, MKC_D); KC2MKCAssignOne(XK_E, MKC_E); KC2MKCAssignOne(XK_F, MKC_F); KC2MKCAssignOne(XK_G, MKC_G); KC2MKCAssignOne(XK_H, MKC_H); KC2MKCAssignOne(XK_I, MKC_I); KC2MKCAssignOne(XK_J, MKC_J); KC2MKCAssignOne(XK_K, MKC_K); KC2MKCAssignOne(XK_L, MKC_L); KC2MKCAssignOne(XK_M, MKC_M); KC2MKCAssignOne(XK_N, MKC_N); KC2MKCAssignOne(XK_O, MKC_O); KC2MKCAssignOne(XK_P, MKC_P); KC2MKCAssignOne(XK_Q, MKC_Q); KC2MKCAssignOne(XK_R, MKC_R); KC2MKCAssignOne(XK_S, MKC_S); KC2MKCAssignOne(XK_T, MKC_T); KC2MKCAssignOne(XK_U, MKC_U); KC2MKCAssignOne(XK_V, MKC_V); KC2MKCAssignOne(XK_W, MKC_W); KC2MKCAssignOne(XK_X, MKC_X); KC2MKCAssignOne(XK_Y, MKC_Y); KC2MKCAssignOne(XK_Z, MKC_Z); TheCapsLockCode = XKeysymToKeycode(x_display, XK_Caps_Lock); InitKeyCodes(); return true; } LOCALPROC CheckTheCapsLock(void) { int NewMousePosh; int NewMousePosv; int root_x_return; int root_y_return; Window root_return; Window child_return; unsigned int mask_return; XQueryPointer(x_display, main_wind, &root_return, &child_return, &root_x_return, &root_y_return, &NewMousePosh, &NewMousePosv, &mask_return); Keyboard_UpdateKeyMap2(MKC_formac_CapsLock, (mask_return & LockMask) != 0); } LOCALPROC DoKeyCode0(int i, bool down) { uint8_t key = KC2MKC[i]; if (MKC_None != key) { Keyboard_UpdateKeyMap2(key, down); } } LOCALPROC DoKeyCode(int i, bool down) { if (i == TheCapsLockCode) { CheckTheCapsLock(); } else if (i >= 0 && i < 256) { DoKeyCode0(i, down); } } #if MayFullScreen && GrabKeysFullScreen LOCALVAR bool KeyboardIsGrabbed = false; #endif #if MayFullScreen && GrabKeysFullScreen LOCALPROC GrabKeyboard(void) { if (! KeyboardIsGrabbed) { (void) XGrabKeyboard(x_display, main_wind, False, GrabModeAsync, GrabModeAsync, CurrentTime); KeyboardIsGrabbed = true; } } #endif #if MayFullScreen && GrabKeysFullScreen LOCALPROC UnGrabKeyboard(void) { if (KeyboardIsGrabbed && main_wind) { XUngrabKeyboard(x_display, CurrentTime); KeyboardIsGrabbed = false; } } #endif LOCALVAR bool NoKeyRepeat = false; LOCALVAR int SaveKeyRepeat; LOCALPROC DisableKeyRepeat(void) { XKeyboardState r; XKeyboardControl k; if ((! NoKeyRepeat) && (x_display != NULL)) { NoKeyRepeat = true; XGetKeyboardControl(x_display, &r); SaveKeyRepeat = r.global_auto_repeat; k.auto_repeat_mode = AutoRepeatModeOff; XChangeKeyboardControl(x_display, KBAutoRepeatMode, &k); } } LOCALPROC RestoreKeyRepeat(void) { XKeyboardControl k; if (NoKeyRepeat && (x_display != NULL)) { NoKeyRepeat = false; k.auto_repeat_mode = SaveKeyRepeat; XChangeKeyboardControl(x_display, KBAutoRepeatMode, &k); } } LOCALVAR bool WantCmdOptOnReconnect = false; LOCALPROC GetTheDownKeys(void) { char keys_return[32]; int i; int v; int j; XQueryKeymap(x_display, keys_return); for (i = 0; i < 32; ++i) { v = keys_return[i]; for (j = 0; j < 8; ++j) { if (0 != ((1 << j) & v)) { int k = i * 8 + j; if (k != TheCapsLockCode) { DoKeyCode0(k, true); } } } } } LOCALPROC ReconnectKeyCodes3(void) { CheckTheCapsLock(); if (WantCmdOptOnReconnect) { WantCmdOptOnReconnect = false; GetTheDownKeys(); } } LOCALPROC DisconnectKeyCodes3(void) { DisconnectKeyCodes2(); MouseButtonSet(false); } /* --- time, date, location --- */ #define dbglog_TimeStuff (0 && dbglog_HAVE) LOCALVAR uint32_t TrueEmulatedTime = 0; #include "UTIL/DATE2SEC.h" #define TicksPerSecond 1000000 LOCALVAR bool HaveTimeDelta = false; LOCALVAR uint32_t TimeDelta; LOCALVAR uint32_t NewMacDateInSeconds; LOCALVAR uint32_t LastTimeSec; LOCALVAR uint32_t LastTimeUsec; LOCALPROC GetCurrentTicks(void) { struct timeval t; gettimeofday(&t, NULL); if (! HaveTimeDelta) { time_t Current_Time; struct tm *s; (void) time(&Current_Time); s = localtime(&Current_Time); TimeDelta = Date2MacSeconds(s->tm_sec, s->tm_min, s->tm_hour, s->tm_mday, 1 + s->tm_mon, 1900 + s->tm_year) - t.tv_sec; #if 0 && AutoTimeZone /* how portable is this ? */ CurMacDelta = ((uint32_t)(s->tm_gmtoff) & 0x00FFFFFF) | ((s->tm_isdst ? 0x80 : 0) << 24); #endif HaveTimeDelta = true; } NewMacDateInSeconds = t.tv_sec + TimeDelta; LastTimeSec = (uint32_t)t.tv_sec; LastTimeUsec = (uint32_t)t.tv_usec; } #define InvTimeStep 16626 /* TicksPerSecond / 60.14742 */ LOCALVAR uint32_t NextTimeSec; LOCALVAR uint32_t NextTimeUsec; LOCALPROC IncrNextTime(void) { NextTimeUsec += InvTimeStep; if (NextTimeUsec >= TicksPerSecond) { NextTimeUsec -= TicksPerSecond; NextTimeSec += 1; } } LOCALPROC InitNextTime(void) { NextTimeSec = LastTimeSec; NextTimeUsec = LastTimeUsec; IncrNextTime(); } LOCALPROC StartUpTimeAdjust(void) { GetCurrentTicks(); InitNextTime(); } LOCALFUNC int32_t GetTimeDiff(void) { return ((int32_t)(LastTimeSec - NextTimeSec)) * TicksPerSecond + ((int32_t)(LastTimeUsec - NextTimeUsec)); } LOCALPROC UpdateTrueEmulatedTime(void) { int32_t TimeDiff; GetCurrentTicks(); TimeDiff = GetTimeDiff(); if (TimeDiff >= 0) { if (TimeDiff > 16 * InvTimeStep) { /* emulation interrupted, forget it */ ++TrueEmulatedTime; InitNextTime(); #if dbglog_TimeStuff dbglog_writelnNum("emulation interrupted", TrueEmulatedTime); #endif } else { do { ++TrueEmulatedTime; IncrNextTime(); TimeDiff -= TicksPerSecond; } while (TimeDiff >= 0); } } else if (TimeDiff < - 16 * InvTimeStep) { /* clock goofed if ever get here, reset */ #if dbglog_TimeStuff dbglog_writeln("clock set back"); #endif InitNextTime(); } } LOCALFUNC bool CheckDateTime(void) { if (CurMacDateInSeconds != NewMacDateInSeconds) { CurMacDateInSeconds = NewMacDateInSeconds; return true; } else { return false; } } LOCALFUNC bool InitLocationDat(void) { GetCurrentTicks(); CurMacDateInSeconds = NewMacDateInSeconds; return true; } /* --- sound --- */ #if SoundEnabled #define kLn2SoundBuffers 4 /* kSoundBuffers must be a power of two */ #define kSoundBuffers (1 << kLn2SoundBuffers) #define kSoundBuffMask (kSoundBuffers - 1) #define DesiredMinFilledSoundBuffs 3 /* if too big then sound lags behind emulation. if too small then sound will have pauses. */ #define kLnOneBuffLen 9 #define kLnAllBuffLen (kLn2SoundBuffers + kLnOneBuffLen) #define kOneBuffLen (1UL << kLnOneBuffLen) #define kAllBuffLen (1UL << kLnAllBuffLen) #define kLnOneBuffSz (kLnOneBuffLen + kLn2SoundSampSz - 3) #define kLnAllBuffSz (kLnAllBuffLen + kLn2SoundSampSz - 3) #define kOneBuffSz (1UL << kLnOneBuffSz) #define kAllBuffSz (1UL << kLnAllBuffSz) #define kOneBuffMask (kOneBuffLen - 1) #define kAllBuffMask (kAllBuffLen - 1) #define dbhBufferSize (kAllBuffSz + kOneBuffSz) #define dbglog_SoundStuff (0 && dbglog_HAVE) #define dbglog_SoundBuffStats (0 && dbglog_HAVE) LOCALVAR tpSoundSamp TheSoundBuffer = nullpr; LOCALVAR uint16_t ThePlayOffset; LOCALVAR uint16_t TheFillOffset; LOCALVAR uint16_t TheWriteOffset; LOCALVAR uint16_t MinFilledSoundBuffs; LOCALPROC Sound_Start0(void) { /* Reset variables */ ThePlayOffset = 0; TheFillOffset = 0; TheWriteOffset = 0; MinFilledSoundBuffs = kSoundBuffers; } GLOBALOSGLUFUNC tpSoundSamp Sound_BeginWrite(uint16_t n, uint16_t *actL) { uint16_t ToFillLen = kAllBuffLen - (TheWriteOffset - ThePlayOffset); uint16_t WriteBuffContig = kOneBuffLen - (TheWriteOffset & kOneBuffMask); if (WriteBuffContig < n) { n = WriteBuffContig; } if (ToFillLen < n) { /* overwrite previous buffer */ #if dbglog_SoundStuff dbglog_writeln("sound buffer over flow"); #endif TheWriteOffset -= kOneBuffLen; } *actL = n; return TheSoundBuffer + (TheWriteOffset & kAllBuffMask); } LOCALFUNC bool Sound_EndWrite0(uint16_t actL) { bool v; TheWriteOffset += actL; if (0 != (TheWriteOffset & kOneBuffMask)) { v = false; } else { /* just finished a block */ TheFillOffset = TheWriteOffset; v = true; } return v; } LOCALPROC Sound_SecondNotify0(void) { if (MinFilledSoundBuffs > DesiredMinFilledSoundBuffs) { #if dbglog_SoundStuff dbglog_writeln("MinFilledSoundBuffs too high"); #endif IncrNextTime(); } else if (MinFilledSoundBuffs < DesiredMinFilledSoundBuffs) { #if dbglog_SoundStuff dbglog_writeln("MinFilledSoundBuffs too low"); #endif ++TrueEmulatedTime; } MinFilledSoundBuffs = kSoundBuffers; } #define SOUND_SAMPLERATE 22255 /* = round(7833600 * 2 / 704) */ //#include "SOUNDGLU.h" #include "HW/SOUND/SGLUALSA.h" #endif /* --- basic dialogs --- */ LOCALPROC CheckSavedMacMsg(void) { /* called only on quit, if error saved but not yet reported */ if (nullpr != SavedBriefMsg) { char briefMsg0[ClStrMaxLength + 1]; char longMsg0[ClStrMaxLength + 1]; NativeStrFromCStr(briefMsg0, SavedBriefMsg); NativeStrFromCStr(longMsg0, SavedLongMsg); fprintf(stderr, "%s\n", briefMsg0); fprintf(stderr, "%s\n", longMsg0); SavedBriefMsg = nullpr; } } /* --- clipboard --- */ #if IncludeHostTextClipExchange LOCALVAR uint8_t * ClipBuffer = NULL; #endif #if IncludeHostTextClipExchange LOCALPROC FreeClipBuffer(void) { if (ClipBuffer != NULL) { free(ClipBuffer); ClipBuffer = NULL; } } #endif #if IncludeHostTextClipExchange GLOBALOSGLUFUNC MacErr_t HTCEexport(tPbuf i) { MacErr_t err = mnvm_miscErr; FreeClipBuffer(); if (MacRomanTextToNativePtr(i, false, &ClipBuffer)) { XSetSelectionOwner(x_display, XA_CLIPBOARD, main_wind, CurrentTime); err = mnvm_noErr; } PbufDispose(i); return err; } #endif #if IncludeHostTextClipExchange LOCALFUNC bool WaitForClipboardSelection(XEvent *xevent) { struct timespec rqt; struct timespec rmt; int i; for (i = 100; --i >= 0; ) { while (XCheckTypedWindowEvent(x_display, main_wind, SelectionNotify, xevent)) { if (xevent->xselection.selection != XA_CLIPBOARD) { /* not what we were looking for. lose it. (and hope it wasn't too important). */ WriteExtraErr("Discarding unwanted SelectionNotify"); } else { /* this is our event */ return true; } } rqt.tv_sec = 0; rqt.tv_nsec = 10000000; (void) nanosleep(&rqt, &rmt); } return false; } #endif #if IncludeHostTextClipExchange LOCALPROC HTCEimport_do(void) { Window w = XGetSelectionOwner(x_display, XA_CLIPBOARD); if (w == main_wind) { /* We own the clipboard, already have ClipBuffer */ } else { FreeClipBuffer(); if (w != None) { XEvent xevent; XDeleteProperty(x_display, main_wind, XA_MinivMac_Clip); XConvertSelection(x_display, XA_CLIPBOARD, XA_STRING, XA_MinivMac_Clip, main_wind, CurrentTime); if (WaitForClipboardSelection(&xevent)) { if (None == xevent.xselection.property) { /* oops, target not supported */ } else { if (xevent.xselection.property != XA_MinivMac_Clip) { /* not where we expected it */ } else { Atom ret_type; int ret_format; unsigned long ret_item; unsigned long remain_byte; unsigned char *s = NULL; if ((Success != XGetWindowProperty( x_display, main_wind, XA_MinivMac_Clip, 0, 65535, False, AnyPropertyType, &ret_type, &ret_format, &ret_item, &remain_byte, &s)) || (ret_type != XA_STRING) || (ret_format != 8) || (NULL == s)) { WriteExtraErr( "XGetWindowProperty failed" " in HTCEimport_do"); } else { ClipBuffer = (uint8_t *)malloc(ret_item + 1); if (NULL == ClipBuffer) { MacMsg(kStrOutOfMemTitle, kStrOutOfMemMessage, false); } else { MoveBytes((anyp)s, (anyp)ClipBuffer, ret_item); ClipBuffer[ret_item] = 0; } XFree(s); } } XDeleteProperty(x_display, main_wind, XA_MinivMac_Clip); } } } } } #endif #if IncludeHostTextClipExchange GLOBALOSGLUFUNC MacErr_t HTCEimport(tPbuf *r) { HTCEimport_do(); return NativeTextToMacRomanPbuf((char *)ClipBuffer, r); } #endif #if IncludeHostTextClipExchange LOCALFUNC bool HandleSelectionRequestClipboard(XEvent *theEvent) { bool RequestFilled = false; #if DbgEvents dbglog_writeln("Requested XA_CLIPBOARD"); #endif if (NULL == ClipBuffer) { /* our clipboard is empty */ } else if (theEvent->xselectionrequest.target == XA_TARGETS) { Atom a[2]; a[0] = XA_TARGETS; a[1] = XA_STRING; XChangeProperty(x_display, theEvent->xselectionrequest.requestor, theEvent->xselectionrequest.property, XA_TARGETS, 32, /* most, but not all, other programs I've look at seem to use 8 here, but that can't be right. can it? */ PropModeReplace, (unsigned char *)a, sizeof(a) / sizeof(Atom)); RequestFilled = true; } else if (theEvent->xselectionrequest.target == XA_STRING) { XChangeProperty(x_display, theEvent->xselectionrequest.requestor, theEvent->xselectionrequest.property, XA_STRING, 8, PropModeReplace, (unsigned char *)ClipBuffer, strlen((char *)ClipBuffer)); RequestFilled = true; } return RequestFilled; } #endif /* --- drag and drop --- */ #if EnableDragDrop LOCALPROC ActivateWind(Time time) { if (NetSupportedContains(XA_NetActiveWindow)) { XEvent xevent; Window rootwin = XRootWindow(x_display, DefaultScreen(x_display)); memset(&xevent, 0, sizeof (xevent)); xevent.xany.type = ClientMessage; xevent.xclient.send_event = True; xevent.xclient.window = main_wind; xevent.xclient.message_type = XA_NetActiveWindow; xevent.xclient.format = 32; xevent.xclient.data.l[0] = 1; xevent.xclient.data.l[1]= time; if (0 == XSendEvent(x_display, rootwin, 0, SubstructureRedirectMask | SubstructureNotifyMask, &xevent)) { WriteExtraErr("XSendEvent failed in ActivateWind"); } } XRaiseWindow(x_display, main_wind); /* In RedHat 7.1, _NET_ACTIVE_WINDOW supported, but XSendEvent of _NET_ACTIVE_WINDOW doesn't raise the window. So just always call XRaiseWindow. Hopefully calling XRaiseWindow won't do any harm on window managers where it isn't needed. (Such as in Ubuntu 5.10) */ XSetInputFocus(x_display, main_wind, RevertToPointerRoot, time); /* And call this always too, just in case */ } #endif #if EnableDragDrop LOCALPROC ParseOneUri(char *s) { /* printf("ParseOneUri %s\n", s); */ if (('f' == s[0]) && ('i' == s[1]) && ('l' == s[2]) && ('e' == s[3]) && (':' == s[4])) { s += 5; if (('/' == s[0]) && ('/' == s[1])) { /* skip hostname */ char c; s += 2; while ((c = *s) != '/') { if (0 == c) { return; } ++s; } } (void) Sony_Insert1a(s, false); } } #endif #if EnableDragDrop LOCALFUNC int HexChar2Nib(char x) { if ((x >= '0') && (x <= '9')) { return x - '0'; } else if ((x >= 'A') && (x <= 'F')) { return x - 'A' + 10; } else if ((x >= 'a') && (x <= 'f')) { return x - 'a' + 10; } else { return -1; } } #endif #if EnableDragDrop LOCALPROC ParseUriList(char *s) { char *p1 = s; char *p0 = s; char *p = s; char c; /* printf("ParseUriList %s\n", s); */ while ((c = *p++) != 0) { if ('%' == c) { int a; int b; if (((a = HexChar2Nib(p[0])) >= 0) && ((b = HexChar2Nib(p[1])) >= 0)) { p += 2; *p1++ = (a << 4) + b; } else { *p1++ = c; } } else if (('\n' == c) || ('\r' == c)) { *p1++ = 0; ParseOneUri(p0); p0 = p1; } else { *p1++ = c; } } *p1++ = 0; ParseOneUri(p0); } #endif #if EnableDragDrop LOCALVAR Window PendingDragWindow = None; #endif #if EnableDragDrop LOCALPROC HandleSelectionNotifyDnd(XEvent *theEvent) { bool DropOk = false; #if DbgEvents dbglog_writeln("Got XA_DndSelection"); #endif if ((theEvent->xselection.property == XA_MinivMac_DndXchng) && (theEvent->xselection.target == XA_UriList)) { Atom ret_type; int ret_format; unsigned long ret_item; unsigned long remain_byte; unsigned char *s = NULL; if ((Success != XGetWindowProperty(x_display, main_wind, XA_MinivMac_DndXchng, 0, 65535, False, XA_UriList, &ret_type, &ret_format, &ret_item, &remain_byte, &s)) || (NULL == s)) { WriteExtraErr( "XGetWindowProperty failed in SelectionNotify"); } else { ParseUriList((char *)s); DropOk = true; XFree(s); } } else { WriteExtraErr("Got Unknown SelectionNotify"); } XDeleteProperty(x_display, main_wind, XA_MinivMac_DndXchng); if (PendingDragWindow != None) { XEvent xevent; memset(&xevent, 0, sizeof(xevent)); xevent.xany.type = ClientMessage; xevent.xany.display = x_display; xevent.xclient.window = PendingDragWindow; xevent.xclient.message_type = XA_DndFinished; xevent.xclient.format = 32; xevent.xclient.data.l[0] = main_wind; if (DropOk) { xevent.xclient.data.l[1] = 1; } xevent.xclient.data.l[2] = XA_DndActionPrivate; if (0 == XSendEvent(x_display, PendingDragWindow, 0, 0, &xevent)) { WriteExtraErr("XSendEvent failed in SelectionNotify"); } } if (DropOk && gTrueBackgroundFlag) { ActivateWind(theEvent->xselection.time); WantCmdOptOnReconnect = true; } } #endif #if EnableDragDrop LOCALPROC HandleClientMessageDndPosition(XEvent *theEvent) { XEvent xevent; int xr; int yr; unsigned int dr; unsigned int wr; unsigned int hr; unsigned int bwr; Window rr; Window srcwin = theEvent->xclient.data.l[0]; #if DbgEvents dbglog_writeln("Got XdndPosition"); #endif XGetGeometry(x_display, main_wind, &rr, &xr, &yr, &wr, &hr, &bwr, &dr); memset (&xevent, 0, sizeof(xevent)); xevent.xany.type = ClientMessage; xevent.xany.display = x_display; xevent.xclient.window = srcwin; xevent.xclient.message_type = XA_DndStatus; xevent.xclient.format = 32; xevent.xclient.data.l[0] = theEvent->xclient.window; /* Target Window */ xevent.xclient.data.l[1] = 1; /* Accept */ xevent.xclient.data.l[2] = ((xr) << 16) | ((yr) & 0xFFFFUL); xevent.xclient.data.l[3] = ((wr) << 16) | ((hr) & 0xFFFFUL); xevent.xclient.data.l[4] = XA_DndActionPrivate; /* Action */ if (0 == XSendEvent(x_display, srcwin, 0, 0, &xevent)) { WriteExtraErr( "XSendEvent failed in HandleClientMessageDndPosition"); } } #endif #if EnableDragDrop LOCALPROC HandleClientMessageDndDrop(XEvent *theEvent) { Time timestamp = theEvent->xclient.data.l[2]; PendingDragWindow = (Window) theEvent->xclient.data.l[0]; #if DbgEvents dbglog_writeln("Got XdndDrop"); #endif XConvertSelection(x_display, XA_DndSelection, XA_UriList, XA_MinivMac_DndXchng, main_wind, timestamp); } #endif #define UseMotionEvents 1 #if UseMotionEvents LOCALVAR bool CaughtMouse = false; #endif #if MayNotFullScreen LOCALVAR int SavedTransH; LOCALVAR int SavedTransV; #endif /* --- event handling for main window --- */ LOCALPROC HandleTheEvent(XEvent *theEvent) { if (theEvent->xany.display != x_display) { WriteExtraErr("Got event for some other display"); } else switch(theEvent->type) { case KeyPress: if (theEvent->xkey.window != main_wind) { WriteExtraErr("Got KeyPress for some other window"); } else { #if DbgEvents dbglog_writeln("- event - KeyPress"); #endif MousePositionNotify(theEvent->xkey.x, theEvent->xkey.y); DoKeyCode(theEvent->xkey.keycode, true); } break; case KeyRelease: if (theEvent->xkey.window != main_wind) { WriteExtraErr("Got KeyRelease for some other window"); } else { #if DbgEvents dbglog_writeln("- event - KeyRelease"); #endif MousePositionNotify(theEvent->xkey.x, theEvent->xkey.y); DoKeyCode(theEvent->xkey.keycode, false); } break; case ButtonPress: /* any mouse button, we don't care which */ if (theEvent->xbutton.window != main_wind) { WriteExtraErr("Got ButtonPress for some other window"); } else { /* could check some modifiers, but don't bother for now Keyboard_UpdateKeyMap2(MKC_formac_CapsLock, (theEvent->xbutton.state & LockMask) != 0); */ MousePositionNotify( theEvent->xbutton.x, theEvent->xbutton.y); MouseButtonSet(true); } break; case ButtonRelease: /* any mouse button, we don't care which */ if (theEvent->xbutton.window != main_wind) { WriteExtraErr( "Got ButtonRelease for some other window"); } else { MousePositionNotify( theEvent->xbutton.x, theEvent->xbutton.y); MouseButtonSet(false); } break; #if UseMotionEvents case MotionNotify: if (theEvent->xmotion.window != main_wind) { WriteExtraErr("Got MotionNotify for some other window"); } else { MousePositionNotify( theEvent->xmotion.x, theEvent->xmotion.y); } break; case EnterNotify: if (theEvent->xcrossing.window != main_wind) { WriteExtraErr("Got EnterNotify for some other window"); } else { #if DbgEvents dbglog_writeln("- event - EnterNotify"); #endif CaughtMouse = true; MousePositionNotify( theEvent->xcrossing.x, theEvent->xcrossing.y); } break; case LeaveNotify: if (theEvent->xcrossing.window != main_wind) { WriteExtraErr("Got LeaveNotify for some other window"); } else { #if DbgEvents dbglog_writeln("- event - LeaveNotify"); #endif MousePositionNotify( theEvent->xcrossing.x, theEvent->xcrossing.y); CaughtMouse = false; } break; #endif case Expose: if (theEvent->xexpose.window != main_wind) { WriteExtraErr( "Got SelectionRequest for some other window"); } else { int x0 = theEvent->xexpose.x; int y0 = theEvent->xexpose.y; int x1 = x0 + theEvent->xexpose.width; int y1 = y0 + theEvent->xexpose.height; #if 0 && DbgEvents dbglog_writeln("- event - Expose"); #endif #if 1 if (UseFullScreen) #endif #if MayFullScreen { x0 -= hOffset; y0 -= vOffset; x1 -= hOffset; y1 -= vOffset; } #endif #if 1 if (UseMagnify) { x0 /= WindowScale; y0 /= WindowScale; x1 = (x1 + (WindowScale - 1)) / WindowScale; y1 = (y1 + (WindowScale - 1)) / WindowScale; } #endif #if 1 if (UseFullScreen) #endif #if MayFullScreen { x0 += ViewHStart; y0 += ViewVStart; x1 += ViewHStart; y1 += ViewVStart; } #endif if (x0 < 0) { x0 = 0; } if (x1 > vMacScreenWidth) { x1 = vMacScreenWidth; } if (y0 < 0) { y0 = 0; } if (y1 > vMacScreenHeight) { y1 = vMacScreenHeight; } if ((x0 < x1) && (y0 < y1)) { HaveChangedScreenBuff(y0, x0, y1, x1); } NeedFinishOpen1 = false; } break; #if IncludeHostTextClipExchange case SelectionRequest: if (theEvent->xselectionrequest.owner != main_wind) { WriteExtraErr( "Got SelectionRequest for some other window"); } else { XEvent xevent; bool RequestFilled = false; #if DbgEvents dbglog_writeln("- event - SelectionRequest"); WriteDbgAtom("selection", theEvent->xselectionrequest.selection); WriteDbgAtom("target", theEvent->xselectionrequest.target); WriteDbgAtom("property", theEvent->xselectionrequest.property); #endif if (theEvent->xselectionrequest.selection == XA_CLIPBOARD) { RequestFilled = HandleSelectionRequestClipboard(theEvent); } memset(&xevent, 0, sizeof(xevent)); xevent.xselection.type = SelectionNotify; xevent.xselection.display = x_display; xevent.xselection.requestor = theEvent->xselectionrequest.requestor; xevent.xselection.selection = theEvent->xselectionrequest.selection; xevent.xselection.target = theEvent->xselectionrequest.target; xevent.xselection.property = (! RequestFilled) ? None : theEvent->xselectionrequest.property ; xevent.xselection.time = theEvent->xselectionrequest.time; if (0 == XSendEvent(x_display, xevent.xselection.requestor, False, 0, &xevent)) { WriteExtraErr( "XSendEvent failed in SelectionRequest"); } } break; case SelectionClear: if (theEvent->xselectionclear.window != main_wind) { WriteExtraErr( "Got SelectionClear for some other window"); } else { #if DbgEvents dbglog_writeln("- event - SelectionClear"); WriteDbgAtom("selection", theEvent->xselectionclear.selection); #endif if (theEvent->xselectionclear.selection == XA_CLIPBOARD) { FreeClipBuffer(); } } break; #endif #if EnableDragDrop case SelectionNotify: if (theEvent->xselection.requestor != main_wind) { WriteExtraErr( "Got SelectionNotify for some other window"); } else { #if DbgEvents dbglog_writeln("- event - SelectionNotify"); WriteDbgAtom("selection", theEvent->xselection.selection); WriteDbgAtom("target", theEvent->xselection.target); WriteDbgAtom("property", theEvent->xselection.property); #endif if (theEvent->xselection.selection == XA_DndSelection) { HandleSelectionNotifyDnd(theEvent); } else { WriteExtraErr( "Got Unknown selection in SelectionNotify"); } } break; #endif case ClientMessage: if (theEvent->xclient.window != main_wind) { WriteExtraErr( "Got ClientMessage for some other window"); } else { #if DbgEvents dbglog_writeln("- event - ClientMessage"); WriteDbgAtom("message_type", theEvent->xclient.message_type); #endif #if EnableDragDrop if (theEvent->xclient.message_type == XA_DndEnter) { /* printf("Got XdndEnter\n"); */ } else if (theEvent->xclient.message_type == XA_DndLeave) { /* printf("Got XdndLeave\n"); */ } else if (theEvent->xclient.message_type == XA_DndPosition) { HandleClientMessageDndPosition(theEvent); } else if (theEvent->xclient.message_type == XA_DndDrop) { HandleClientMessageDndDrop(theEvent); } else #endif { if ((32 == theEvent->xclient.format) && (theEvent->xclient.data.l[0] == XA_DeleteW)) { /* I would think that should test that WM_PROTOCOLS == message_type but none of the other programs I looked at did. */ RequestMacOff = true; } } } break; case FocusIn: if (theEvent->xfocus.window != main_wind) { WriteExtraErr("Got FocusIn for some other window"); } else { #if DbgEvents dbglog_writeln("- event - FocusIn"); #endif gTrueBackgroundFlag = false; #if UseMotionEvents CheckMouseState(); /* Doesn't help on x11 for OS X, can't get new mouse position in any fashion until mouse moves. */ #endif } break; case FocusOut: if (theEvent->xfocus.window != main_wind) { WriteExtraErr("Got FocusOut for some other window"); } else { #if DbgEvents dbglog_writeln("- event - FocusOut"); #endif gTrueBackgroundFlag = true; } break; default: break; } } /* --- main window creation and disposal --- */ LOCALVAR int argc; LOCALVAR char **argv; LOCALVAR char *display_name = NULL; LOCALFUNC bool Screen_Init(void) { Window rootwin; int screen; Colormap Xcmap; Visual *Xvisual; x_display = XOpenDisplay(display_name); if (NULL == x_display) { fprintf(stderr, "Cannot connect to X server.\n"); return false; } screen = DefaultScreen(x_display); rootwin = XRootWindow(x_display, screen); Xcmap = DefaultColormap(x_display, screen); Xvisual = DefaultVisual(x_display, screen); LoadXA(); XParseColor(x_display, Xcmap, "#000000", &x_black); if (! XAllocColor(x_display, Xcmap, &x_black)) { WriteExtraErr("XParseColor black fails"); } XParseColor(x_display, Xcmap, "#ffffff", &x_white); if (! XAllocColor(x_display, Xcmap, &x_white)) { WriteExtraErr("XParseColor white fails"); } if (! CreateBlankCursor(rootwin)) { return false; } #if ! UseColorImage image = XCreateImage(x_display, Xvisual, 1, XYBitmap, 0, NULL /* (char *)image_Mem1 */, vMacScreenWidth, vMacScreenHeight, 32, vMacScreenMonoByteWidth); if (NULL == image) { fprintf(stderr, "XCreateImage failed.\n"); return false; } #if 0 fprintf(stderr, "bitmap_bit_order = %d\n", (int)image->bitmap_bit_order); fprintf(stderr, "byte_order = %d\n", (int)image->byte_order); #endif image->bitmap_bit_order = MSBFirst; image->byte_order = MSBFirst; #endif #if UseColorImage image = XCreateImage(x_display, Xvisual, 24, ZPixmap, 0, NULL /* (char *)image_Mem1 */, vMacScreenWidth, vMacScreenHeight, 32, 4 * (uint32_t)vMacScreenWidth); if (NULL == image) { fprintf(stderr, "XCreateImage Color failed.\n"); return false; } #if 0 fprintf(stderr, "DefaultDepth = %d\n", (int)DefaultDepth(x_display, screen)); fprintf(stderr, "MSBFirst = %d\n", (int)MSBFirst); fprintf(stderr, "LSBFirst = %d\n", (int)LSBFirst); fprintf(stderr, "bitmap_bit_order = %d\n", (int)image->bitmap_bit_order); fprintf(stderr, "byte_order = %d\n", (int)image->byte_order); fprintf(stderr, "bitmap_unit = %d\n", (int)image->bitmap_unit); fprintf(stderr, "bits_per_pixel = %d\n", (int)image->bits_per_pixel); fprintf(stderr, "red_mask = %d\n", (int)image->red_mask); fprintf(stderr, "green_mask = %d\n", (int)image->green_mask); fprintf(stderr, "blue_mask = %d\n", (int)image->blue_mask); #endif #endif /* UseColorImage */ #if 1 && (! UseColorImage) Scaled_image = XCreateImage(x_display, Xvisual, 1, XYBitmap, 0, NULL /* (char *)image_Mem1 */, vMacScreenWidth * WindowScale, vMacScreenHeight * WindowScale, 32, vMacScreenMonoByteWidth * WindowScale); if (NULL == Scaled_image) { fprintf(stderr, "XCreateImage failed.\n"); return false; } Scaled_image->bitmap_bit_order = MSBFirst; Scaled_image->byte_order = MSBFirst; #endif #if 1 && UseColorImage Scaled_image = XCreateImage(x_display, Xvisual, 24, ZPixmap, 0, NULL /* (char *)image_Mem1 */, vMacScreenWidth * WindowScale, vMacScreenHeight * WindowScale, 32, 4 * (uint32_t)vMacScreenWidth * WindowScale); if (NULL == Scaled_image) { fprintf(stderr, "XCreateImage Scaled failed.\n"); return false; } #endif #if 0 != vMacScreenDepth ColorModeWorks = true; #endif DisableKeyRepeat(); return true; } LOCALPROC CloseMainWindow(void) { if (gc != NULL) { XFreeGC(x_display, gc); gc = NULL; } if (main_wind) { XDestroyWindow(x_display, main_wind); main_wind = 0; } } enum { kMagStateNormal, #if 1 kMagStateMagnifgy, #endif kNumMagStates }; #define kMagStateAuto kNumMagStates #if MayNotFullScreen LOCALVAR int CurWinIndx; LOCALVAR bool HavePositionWins[kNumMagStates]; LOCALVAR int WinPositionWinsH[kNumMagStates]; LOCALVAR int WinPositionWinsV[kNumMagStates]; #endif #if EnableRecreateW LOCALPROC ZapWState(void) { main_wind = 0; gc = NULL; } #endif LOCALFUNC bool CreateMainWindow(void) { Window rootwin; int screen; int xr; int yr; unsigned int dr; unsigned int wr; unsigned int hr; unsigned int bwr; Window rr; int leftPos; int topPos; #if MayNotFullScreen int WinIndx; #endif #if EnableDragDrop long int xdnd_version = 5; #endif int NewWindowHeight = vMacScreenHeight; int NewWindowWidth = vMacScreenWidth; /* Get connection to X Server */ screen = DefaultScreen(x_display); rootwin = XRootWindow(x_display, screen); XGetGeometry(x_display, rootwin, &rr, &xr, &yr, &wr, &hr, &bwr, &dr); #if 1 if (UseMagnify) { NewWindowHeight *= WindowScale; NewWindowWidth *= WindowScale; } #endif if (wr > NewWindowWidth) { leftPos = (wr - NewWindowWidth) / 2; } else { leftPos = 0; } if (hr > NewWindowHeight) { topPos = (hr - NewWindowHeight) / 2; } else { topPos = 0; } #if 1 if (UseFullScreen) #endif #if MayFullScreen { ViewHSize = wr; ViewVSize = hr; #if 1 if (UseMagnify) { ViewHSize /= WindowScale; ViewVSize /= WindowScale; } #endif if (ViewHSize >= vMacScreenWidth) { ViewHStart = 0; ViewHSize = vMacScreenWidth; } else { ViewHSize &= ~ 1; } if (ViewVSize >= vMacScreenHeight) { ViewVStart = 0; ViewVSize = vMacScreenHeight; } else { ViewVSize &= ~ 1; } } #endif #if 1 if (! UseFullScreen) #endif #if MayNotFullScreen { #if 1 if (UseMagnify) { WinIndx = kMagStateMagnifgy; } else #endif { WinIndx = kMagStateNormal; } if (! HavePositionWins[WinIndx]) { WinPositionWinsH[WinIndx] = leftPos; WinPositionWinsV[WinIndx] = topPos; HavePositionWins[WinIndx] = true; } else { leftPos = WinPositionWinsH[WinIndx]; topPos = WinPositionWinsV[WinIndx]; } } #endif #if 1 if (UseFullScreen) #endif #if MayFullScreen { XSetWindowAttributes xattr; xattr.override_redirect = True; xattr.background_pixel = x_black.pixel; xattr.border_pixel = x_white.pixel; main_wind = XCreateWindow(x_display, rr, 0, 0, wr, hr, 0, CopyFromParent, /* depth */ InputOutput, /* class */ CopyFromParent, /* visual */ CWOverrideRedirect | CWBackPixel | CWBorderPixel, /* valuemask */ &xattr /* attributes */); } #endif #if 1 else #endif #if MayNotFullScreen { main_wind = XCreateSimpleWindow(x_display, rootwin, leftPos, topPos, NewWindowWidth, NewWindowHeight, 4, x_white.pixel, x_black.pixel); } #endif if (! main_wind) { WriteExtraErr("XCreateSimpleWindow failed."); return false; } else { char *win_name = (NULL != n_arg) ? n_arg : ( #ifdef CanGetAppPath (NULL != app_name) ? app_name : #endif kStrAppName); XSelectInput(x_display, main_wind, ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask #if UseMotionEvents | PointerMotionMask | EnterWindowMask | LeaveWindowMask #endif | FocusChangeMask); XStoreName(x_display, main_wind, win_name); XSetIconName(x_display, main_wind, win_name); { XClassHint *hints = XAllocClassHint(); if (hints) { hints->res_name = kStrAppName; hints->res_class = kStrAppName; XSetClassHint(x_display, main_wind, hints); XFree(hints); } } { XWMHints *hints = XAllocWMHints(); if (hints) { hints->input = True; hints->initial_state = NormalState; hints->flags = InputHint | StateHint; XSetWMHints(x_display, main_wind, hints); XFree(hints); } } XSetCommand(x_display, main_wind, argv, argc); /* let us handle a click on the close box */ XSetWMProtocols(x_display, main_wind, &XA_DeleteW, 1); #if EnableDragDrop XChangeProperty (x_display, main_wind, XA_DndAware, XA_ATOM, 32, PropModeReplace, (unsigned char *) &xdnd_version, 1); #endif gc = XCreateGC(x_display, main_wind, 0, NULL); if (NULL == gc) { WriteExtraErr("XCreateGC failed."); return false; } XSetState(x_display, gc, x_black.pixel, x_white.pixel, GXcopy, AllPlanes); #if 1 if (! UseFullScreen) #endif #if MayNotFullScreen { XSizeHints *hints = XAllocSizeHints(); if (hints) { hints->min_width = NewWindowWidth; hints->max_width = NewWindowWidth; hints->min_height = NewWindowHeight; hints->max_height = NewWindowHeight; /* Try again to say where the window ought to go. I've seen this described as obsolete, but it seems to work on all x implementations tried so far, and nothing else does. */ hints->x = leftPos; hints->y = topPos; hints->width = NewWindowWidth; hints->height = NewWindowHeight; hints->flags = PMinSize | PMaxSize | PPosition | PSize; XSetWMNormalHints(x_display, main_wind, hints); XFree(hints); } } #endif #if 1 if (UseFullScreen) #endif #if MayFullScreen { hOffset = leftPos; vOffset = topPos; } #endif DisconnectKeyCodes3(); /* since will lose keystrokes to old window */ #if MayNotFullScreen CurWinIndx = WinIndx; #endif XMapRaised(x_display, main_wind); #if 0 XSync(x_display, 0); #endif #if 0 /* This helps in Red Hat 9 to get the new window activated, and I've seen other programs do similar things. */ /* In current scheme, haven't closed old window yet. If old window full screen, never receive expose event for new one. */ { XEvent event; do { XNextEvent(x_display, &event); HandleTheEvent(&event); } while (! ((Expose == event.type) && (event.xexpose.window == main_wind))); } #endif NeedFinishOpen1 = true; NeedFinishOpen2 = true; return true; } } #if MayFullScreen LOCALVAR bool GrabMachine = false; #endif #if MayFullScreen LOCALPROC GrabTheMachine(void) { #if EnableFSMouseMotion StartSaveMouseMotion(); #endif #if GrabKeysFullScreen GrabKeyboard(); #endif } #endif #if MayFullScreen LOCALPROC UngrabMachine(void) { #if EnableFSMouseMotion StopSaveMouseMotion(); #endif #if GrabKeysFullScreen UnGrabKeyboard(); #endif } #endif #if EnableRecreateW struct WState { Window f_main_wind; GC f_gc; #if MayFullScreen short f_hOffset; short f_vOffset; uint16_t f_ViewHSize; uint16_t f_ViewVSize; uint16_t f_ViewHStart; uint16_t f_ViewVStart; #endif #if 1 bool f_UseFullScreen; #endif #if 1 bool f_UseMagnify; #endif }; typedef struct WState WState; #endif #if EnableRecreateW LOCALPROC GetWState(WState *r) { r->f_main_wind = main_wind; r->f_gc = gc; #if MayFullScreen r->f_hOffset = hOffset; r->f_vOffset = vOffset; r->f_ViewHSize = ViewHSize; r->f_ViewVSize = ViewVSize; r->f_ViewHStart = ViewHStart; r->f_ViewVStart = ViewVStart; #endif #if 1 r->f_UseFullScreen = UseFullScreen; #endif #if 1 r->f_UseMagnify = UseMagnify; #endif } #endif #if EnableRecreateW LOCALPROC SetWState(WState *r) { main_wind = r->f_main_wind; gc = r->f_gc; #if MayFullScreen hOffset = r->f_hOffset; vOffset = r->f_vOffset; ViewHSize = r->f_ViewHSize; ViewVSize = r->f_ViewVSize; ViewHStart = r->f_ViewHStart; ViewVStart = r->f_ViewVStart; #endif #if 1 UseFullScreen = r->f_UseFullScreen; #endif #if 1 UseMagnify = r->f_UseMagnify; #endif } #endif #if EnableRecreateW LOCALVAR bool WantRestoreCursPos = false; LOCALVAR uint16_t RestoreMouseH; LOCALVAR uint16_t RestoreMouseV; #endif #if EnableRecreateW LOCALFUNC bool ReCreateMainWindow(void) { WState old_state; WState new_state; #if IncludeHostTextClipExchange bool OwnClipboard = false; #endif if (HaveCursorHidden) { WantRestoreCursPos = true; RestoreMouseH = CurMouseH; RestoreMouseV = CurMouseV; } ForceShowCursor(); /* hide/show cursor api is per window */ #if MayNotFullScreen #if 1 if (! UseFullScreen) #endif if (main_wind) if (! NeedFinishOpen2) { /* save old position */ int xr; int yr; unsigned int dr; unsigned int wr; unsigned int hr; unsigned int bwr; Window rr; Window rr2; /* Get connection to X Server */ int screen = DefaultScreen(x_display); Window rootwin = XRootWindow(x_display, screen); XGetGeometry(x_display, rootwin, &rr, &xr, &yr, &wr, &hr, &bwr, &dr); /* Couldn't reliably find out where window is now, due to what seem to be some broken X implementations, and so instead track how far window has moved. */ XSync(x_display, 0); if (XTranslateCoordinates(x_display, main_wind, rootwin, 0, 0, &xr, &yr, &rr2)) { int newposh = WinPositionWinsH[CurWinIndx] + (xr - SavedTransH); int newposv = WinPositionWinsV[CurWinIndx] + (yr - SavedTransV); if ((newposv > 0) && (newposv < hr) && (newposh < wr)) { WinPositionWinsH[CurWinIndx] = newposh; WinPositionWinsV[CurWinIndx] = newposv; SavedTransH = xr; SavedTransV = yr; } } } #endif #if MayFullScreen if (GrabMachine) { GrabMachine = false; UngrabMachine(); } #endif GetWState(&old_state); ZapWState(); #if 1 UseMagnify = WantMagnify; #endif #if 1 UseFullScreen = WantFullScreen; #endif ColorTransValid = false; if (! CreateMainWindow()) { CloseMainWindow(); SetWState(&old_state); /* avoid retry */ #if 1 WantFullScreen = UseFullScreen; #endif #if 1 WantMagnify = UseMagnify; #endif return false; } else { GetWState(&new_state); SetWState(&old_state); #if IncludeHostTextClipExchange if (main_wind) { if (XGetSelectionOwner(x_display, XA_CLIPBOARD) == main_wind) { OwnClipboard = true; } } #endif CloseMainWindow(); SetWState(&new_state); #if IncludeHostTextClipExchange if (OwnClipboard) { XSetSelectionOwner(x_display, XA_CLIPBOARD, main_wind, CurrentTime); } #endif } return true; } #endif #if 1 && 1 enum { kWinStateWindowed, #if 1 kWinStateFullScreen, #endif kNumWinStates }; #endif #if 1 && 1 LOCALVAR int WinMagStates[kNumWinStates]; #endif LOCALPROC ZapWinStateVars(void) { #if MayNotFullScreen { int i; for (i = 0; i < kNumMagStates; ++i) { HavePositionWins[i] = false; } } #endif #if 1 && 1 { int i; for (i = 0; i < kNumWinStates; ++i) { WinMagStates[i] = kMagStateAuto; } } #endif } #if 1 LOCALPROC ToggleWantFullScreen(void) { WantFullScreen = ! WantFullScreen; #if 1 { int OldWinState = UseFullScreen ? kWinStateFullScreen : kWinStateWindowed; int OldMagState = UseMagnify ? kMagStateMagnifgy : kMagStateNormal; int NewWinState = WantFullScreen ? kWinStateFullScreen : kWinStateWindowed; int NewMagState = WinMagStates[NewWinState]; WinMagStates[OldWinState] = OldMagState; if (kMagStateAuto != NewMagState) { WantMagnify = (kMagStateMagnifgy == NewMagState); } else { WantMagnify = false; if (WantFullScreen) { Window rootwin; int xr; int yr; unsigned int dr; unsigned int wr; unsigned int hr; unsigned int bwr; Window rr; rootwin = XRootWindow(x_display, DefaultScreen(x_display)); XGetGeometry(x_display, rootwin, &rr, &xr, &yr, &wr, &hr, &bwr, &dr); if ((wr >= vMacScreenWidth * WindowScale) && (hr >= vMacScreenHeight * WindowScale) ) { WantMagnify = true; } } } } #endif } #endif /* --- SavedTasks --- */ LOCALPROC LeaveBackground(void) { ReconnectKeyCodes3(); DisableKeyRepeat(); } LOCALPROC EnterBackground(void) { RestoreKeyRepeat(); DisconnectKeyCodes3(); ForceShowCursor(); } LOCALPROC LeaveSpeedStopped(void) { #if SoundEnabled Sound_Start(); #endif StartUpTimeAdjust(); } LOCALPROC EnterSpeedStopped(void) { #if SoundEnabled Sound_Stop(); #endif } LOCALPROC CheckForSavedTasks(void) { if (EvtQNeedRecover) { EvtQNeedRecover = false; /* attempt cleanup, EvtQNeedRecover may get set again */ EvtQTryRecoverFromFull(); } if (NeedFinishOpen2 && ! NeedFinishOpen1) { NeedFinishOpen2 = false; #if 1 if (UseFullScreen) #endif #if MayFullScreen { XSetInputFocus(x_display, main_wind, RevertToPointerRoot, CurrentTime); } #endif #if 1 else #endif #if MayNotFullScreen { Window rr; int screen = DefaultScreen(x_display); Window rootwin = XRootWindow(x_display, screen); #if 0 /* This doesn't work right in Red Hat 6, and may not be needed anymore, now that using PPosition hint. */ XMoveWindow(x_display, main_wind, leftPos, topPos); /* Needed after XMapRaised, because some window managers will apparently ignore where the window was asked to be put. */ #endif XSync(x_display, 0); /* apparently, XTranslateCoordinates can be inaccurate without this */ XTranslateCoordinates(x_display, main_wind, rootwin, 0, 0, &SavedTransH, &SavedTransV, &rr); } #endif #if EnableRecreateW if (WantRestoreCursPos) { #if EnableFSMouseMotion if (! HaveMouseMotion) #endif { (void) MoveMouse(RestoreMouseH, RestoreMouseV); WantCursorHidden = true; } WantRestoreCursPos = false; } #endif } #if EnableFSMouseMotion if (HaveMouseMotion) { MouseConstrain(); } #endif if (RequestMacOff) { RequestMacOff = false; if (AnyDiskInserted()) { MacMsgOverride(kStrQuitWarningTitle, kStrQuitWarningMessage); } else { ForceMacOff = true; } } if (ForceMacOff) { return; } if (gTrueBackgroundFlag != gBackgroundFlag) { gBackgroundFlag = gTrueBackgroundFlag; if (gTrueBackgroundFlag) { EnterBackground(); } else { LeaveBackground(); } } if (CurSpeedStopped != (SpeedStopped || (gBackgroundFlag && ! RunInBackground))) { CurSpeedStopped = ! CurSpeedStopped; if (CurSpeedStopped) { EnterSpeedStopped(); } else { LeaveSpeedStopped(); } } #if MayFullScreen if (gTrueBackgroundFlag #if 1 && WantFullScreen #endif ) { /* Since often get here on Ubuntu Linux 5.10 running on a slow machine (emulated) when attempt to enter full screen, don't abort full screen, but try to fix it. */ #if 0 ToggleWantFullScreen(); #else XRaiseWindow(x_display, main_wind); XSetInputFocus(x_display, main_wind, RevertToPointerRoot, CurrentTime); #endif } #endif #if EnableRecreateW if (0 #if 1 || (UseMagnify != WantMagnify) #endif #if 1 || (UseFullScreen != WantFullScreen) #endif ) { (void) ReCreateMainWindow(); } #endif #if MayFullScreen if (GrabMachine != ( #if 1 UseFullScreen && #endif ! (gTrueBackgroundFlag || CurSpeedStopped))) { GrabMachine = ! GrabMachine; if (GrabMachine) { GrabTheMachine(); } else { UngrabMachine(); } } #endif #if IncludeSonyNew if (vSonyNewDiskWanted) { #if IncludeSonyNameNew if (vSonyNewDiskName != NotAPbuf) { uint8_t * NewDiskNameDat; if (MacRomanTextToNativePtr(vSonyNewDiskName, true, &NewDiskNameDat)) { MakeNewDisk(vSonyNewDiskSize, (char *)NewDiskNameDat); free(NewDiskNameDat); } PbufDispose(vSonyNewDiskName); vSonyNewDiskName = NotAPbuf; } else #endif { MakeNewDiskAtDefault(vSonyNewDiskSize); } vSonyNewDiskWanted = false; /* must be done after may have gotten disk */ } #endif if ((nullpr != SavedBriefMsg) & ! MacMsgDisplayed) { MacMsgDisplayOn(); } if (NeedWholeScreenDraw) { NeedWholeScreenDraw = false; ScreenChangedAll(); } #if NeedRequestIthDisk if (0 != RequestIthDisk) { Sony_InsertIth(RequestIthDisk); RequestIthDisk = 0; } #endif if (HaveCursorHidden != (WantCursorHidden && ! (gTrueBackgroundFlag || CurSpeedStopped))) { HaveCursorHidden = ! HaveCursorHidden; if (HaveCursorHidden) { XDefineCursor(x_display, main_wind, blankCursor); } else { XUndefineCursor(x_display, main_wind); } } } /* --- command line parsing --- */ LOCALFUNC bool ScanCommandLine(void) { char *pa; int i = 1; label_retry: if (i < argc) { pa = argv[i++]; if ('-' == pa[0]) { if ((0 == strcmp(pa, "--display")) || (0 == strcmp(pa, "-display"))) { if (i < argc) { display_name = argv[i++]; goto label_retry; } } else if ((0 == strcmp(pa, "--rom")) || (0 == strcmp(pa, "-r"))) { if (i < argc) { rom_path = argv[i++]; goto label_retry; } } else if (0 == strcmp(pa, "-n")) { if (i < argc) { n_arg = argv[i++]; goto label_retry; } } else if (0 == strcmp(pa, "-d")) { if (i < argc) { d_arg = argv[i++]; goto label_retry; } } else #ifndef UsingAlsa #define UsingAlsa 0 #endif #if UsingAlsa if ((0 == strcmp(pa, "--alsadev")) || (0 == strcmp(pa, "-alsadev"))) { if (i < argc) { alsadev_name = argv[i++]; goto label_retry; } } else #endif #if 0 if (0 == strcmp(pa, "-l")) { SpeedValue = 0; goto label_retry; } else #endif { MacMsg(kStrBadArgTitle, kStrBadArgMessage, false); } } else { (void) Sony_Insert1(pa, false); goto label_retry; } } return true; } /* --- main program flow --- */ GLOBALOSGLUPROC DoneWithDrawingForTick(void) { #if EnableFSMouseMotion if (HaveMouseMotion) { AutoScrollScreen(); } #endif DrawChangesAndClear(); XFlush(x_display); } GLOBALOSGLUFUNC bool ExtraTimeNotOver(void) { UpdateTrueEmulatedTime(); return TrueEmulatedTime == OnTrueTime; } LOCALPROC WaitForTheNextEvent(void) { XEvent event; XNextEvent(x_display, &event); HandleTheEvent(&event); } LOCALPROC CheckForSystemEvents(void) { int i = 10; while ((XEventsQueued(x_display, QueuedAfterReading) > 0) && (--i >= 0)) { WaitForTheNextEvent(); } } GLOBALOSGLUPROC WaitForNextTick(void) { label_retry: CheckForSystemEvents(); CheckForSavedTasks(); if (ForceMacOff) { return; } if (CurSpeedStopped) { DoneWithDrawingForTick(); WaitForTheNextEvent(); goto label_retry; } if (ExtraTimeNotOver()) { struct timespec rqt; struct timespec rmt; int32_t TimeDiff = GetTimeDiff(); if (TimeDiff < 0) { rqt.tv_sec = 0; rqt.tv_nsec = (- TimeDiff) * 1000; (void) nanosleep(&rqt, &rmt); } goto label_retry; } if (CheckDateTime()) { #if SoundEnabled Sound_SecondNotify(); #endif } if ((! gBackgroundFlag) #if UseMotionEvents && (! CaughtMouse) #endif ) { CheckMouseState(); } OnTrueTime = TrueEmulatedTime; #if dbglog_TimeStuff dbglog_writelnNum("WaitForNextTick, OnTrueTime", OnTrueTime); #endif } /* --- platform independent code can be thought of as going here --- */ #include "PROGMAIN.h" LOCALPROC ZapOSGLUVars(void) { InitDrives(); ZapWinStateVars(); } LOCALPROC ReserveAllocAll(void) { #if dbglog_HAVE dbglog_ReserveAlloc(); #endif ReserveAllocOneBlock(&ROM, kROM_Size, 5, false); ReserveAllocOneBlock(&screencomparebuff, vMacScreenNumBytes, 5, true); #if UseControlKeys ReserveAllocOneBlock(&CntrlDisplayBuff, vMacScreenNumBytes, 5, false); #endif #if WantScalingBuff ReserveAllocOneBlock(&ScalingBuff, ScalingBuffsz, 5, false); #endif #if WantScalingTabl ReserveAllocOneBlock(&ScalingTabl, ScalingTablsz, 5, false); #endif #if SoundEnabled ReserveAllocOneBlock((uint8_t * *)&TheSoundBuffer, dbhBufferSize, 5, false); #endif EmulationReserveAlloc(); } LOCALFUNC bool AllocMemory(void) { uimr n; bool IsOk = false; ReserveAllocOffset = 0; ReserveAllocBigBlock = nullpr; ReserveAllocAll(); n = ReserveAllocOffset; ReserveAllocBigBlock = (uint8_t *)calloc(1, n); if (NULL == ReserveAllocBigBlock) { MacMsg(kStrOutOfMemTitle, kStrOutOfMemMessage, true); } else { ReserveAllocOffset = 0; ReserveAllocAll(); if (n != ReserveAllocOffset) { /* oops, program error */ } else { IsOk = true; } } return IsOk; } LOCALPROC UnallocMemory(void) { if (nullpr != ReserveAllocBigBlock) { free((char *)ReserveAllocBigBlock); } } #ifdef HaveAppPathLink LOCALFUNC bool ReadLink_Alloc(char *path, char **r) { /* This should work to find size: struct stat r; if (lstat(path, &r) != -1) { r = r.st_size; IsOk = true; } But observed to return 0 in Ubuntu 10.04 x86-64 */ char *s; int sz; char *p; bool IsOk = false; size_t s_alloc = 256; label_retry: s = (char *)malloc(s_alloc); if (NULL == s) { fprintf(stderr, "malloc failed.\n"); } else { sz = readlink(path, s, s_alloc); if ((sz < 0) || (sz >= s_alloc)) { free(s); if (sz == s_alloc) { s_alloc <<= 1; goto label_retry; } else { fprintf(stderr, "readlink failed.\n"); } } else { /* ok */ p = (char *)malloc(sz + 1); if (NULL == p) { fprintf(stderr, "malloc failed.\n"); } else { (void) memcpy(p, s, sz); p[sz] = 0; *r = p; IsOk = true; } free(s); } } return IsOk; } #endif #ifdef HaveSysctlPath LOCALFUNC bool ReadKernProcPathname(char **r) { size_t s_alloc; char *s; int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; bool IsOk = false; if (0 != sysctl(mib, sizeof(mib) / sizeof(int), NULL, &s_alloc, NULL, 0)) { fprintf(stderr, "sysctl failed.\n"); } else { s = (char *)malloc(s_alloc); if (NULL == s) { fprintf(stderr, "malloc failed.\n"); } else { if (0 != sysctl(mib, sizeof(mib) / sizeof(int), s, &s_alloc, NULL, 0)) { fprintf(stderr, "sysctl 2 failed.\n"); } else { *r = s; IsOk = true; } if (! IsOk) { free(s); } } } return IsOk; } #endif #ifdef CanGetAppPath LOCALFUNC bool Path2ParentAndName(char *path, char **parent, char **name) { bool IsOk = false; char *t = strrchr(path, '/'); if (NULL == t) { fprintf(stderr, "no directory.\n"); } else { int par_sz = t - path; char *par = (char *)malloc(par_sz + 1); if (NULL == par) { fprintf(stderr, "malloc failed.\n"); } else { (void) memcpy(par, path, par_sz); par[par_sz] = 0; { int s_sz = strlen(path); int child_sz = s_sz - par_sz - 1; char *child = (char *)malloc(child_sz + 1); if (NULL == child) { fprintf(stderr, "malloc failed.\n"); } else { (void) memcpy(child, t + 1, child_sz); child[child_sz] = 0; *name = child; IsOk = true; /* free(child); */ } } if (! IsOk) { free(par); } else { *parent = par; } } } return IsOk; } #endif #ifdef CanGetAppPath LOCALFUNC bool InitWhereAmI(void) { char *s; if (! #ifdef HaveAppPathLink ReadLink_Alloc(TheAppPathLink, &s) #endif #ifdef HaveSysctlPath ReadKernProcPathname(&s) #endif ) { fprintf(stderr, "InitWhereAmI fails.\n"); } else { if (! Path2ParentAndName(s, &app_parent, &app_name)) { fprintf(stderr, "Path2ParentAndName fails.\n"); } else { /* ok */ /* fprintf(stderr, "parent = %s.\n", app_parent); fprintf(stderr, "name = %s.\n", app_name); */ } free(s); } return true; /* keep going regardless */ } #endif #ifdef CanGetAppPath LOCALPROC UninitWhereAmI(void) { MayFree(app_parent); MayFree(app_name); } #endif LOCALFUNC bool InitOSGLU(void) { if (AllocMemory()) #ifdef CanGetAppPath if (InitWhereAmI()) #endif #if dbglog_HAVE if (dbglog_open()) #endif if (ScanCommandLine()) if (LoadMacRom()) if (LoadInitialImages()) if (InitLocationDat()) #if SoundEnabled if (Sound_Init()) #endif if (Screen_Init()) if (CreateMainWindow()) if (KC2MKCInit()) if (WaitForRom()) { return true; } return false; } LOCALPROC UnInitOSGLU(void) { if (MacMsgDisplayed) { MacMsgDisplayOff(); } RestoreKeyRepeat(); #if MayFullScreen UngrabMachine(); #endif #if SoundEnabled Sound_Stop(); #endif #if SoundEnabled Sound_UnInit(); #endif #if IncludeHostTextClipExchange FreeClipBuffer(); #endif #if IncludePbufs UnInitPbufs(); #endif UnInitDrives(); ForceShowCursor(); if (blankCursor != None) { XFreeCursor(x_display, blankCursor); } if (image != NULL) { XDestroyImage(image); } #if 1 if (Scaled_image != NULL) { XDestroyImage(Scaled_image); } #endif CloseMainWindow(); if (x_display != NULL) { XCloseDisplay(x_display); } #if dbglog_HAVE dbglog_close(); #endif #ifdef CanGetAppPath UninitWhereAmI(); #endif UnallocMemory(); CheckSavedMacMsg(); } int main(int argc, char **argv) { argc = argc; argv = argv; ZapOSGLUVars(); if (InitOSGLU()) { ProgramMain(); } UnInitOSGLU(); return 0; }