/* NetHack 3.6 macwin.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */ /* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */ /* NetHack may be freely redistributed. See license for details. */ /********************************************************************** * Imported variables and functions */ #include "hack.h" #include "func_tab.h" #include "macwin.h" #include "mactty.h" #include "wintty.h" #if 1 /*!TARGET_API_MAC_CARBON*/ #include #include #include #include #include #include #endif /********************************************************************** * Local variables and functions */ #if 0 // TARGET_API_MAC_CARBON static EventTypeSpec baseevents[] = { { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassMouse, kEventMouseMoved }, { kEventClassWindow, kEventWindowDrawContent }, { kEventClassWindow, kEventWindowHandleContentClick }, { kEventClassWindow, kEventWindowClose } }; static EventTypeSpec msgevents[] = { { kEventClassControl, kEventControlHit }, { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassWindow, kEventWindowDrawContent }, { kEventClassWindow, kEventWindowHandleContentClick }, { kEventClassWindow, kEventWindowClose } }; static EventTypeSpec menwevents[] = { { kEventClassControl, kEventControlHit }, { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassWindow, kEventWindowDrawContent }, { kEventClassWindow, kEventWindowHandleContentClick }, { kEventClassWindow, kEventWindowClose } }; static EventTypeSpec textevents[] = { { kEventClassControl, kEventControlHit }, { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassWindow, kEventWindowDrawContent }, { kEventClassWindow, kEventWindowClose } }; static EventTypeSpec globalevents[] = { { kEventClassCommand, kEventCommandProcess } }; EventTargetRef dispatcher; EventHandlerUPP baseupp, msgupp, menwupp, textupp; static pascal OSStatus BaseEvent(EventHandlerCallRef, EventRef, void *); static void MsgUpdate(NhWindow *wind); static pascal OSStatus MsgEvent(EventHandlerCallRef, EventRef, void *); static void MenwUpdate(NhWindow *wind); static pascal OSStatus MenwEvent(EventHandlerCallRef, EventRef, void *); static void TextUpdate(NhWindow *wind); static pascal OSStatus TextEvent(EventHandlerCallRef, EventRef, void *); static pascal OSStatus GlobalEvent(EventHandlerCallRef, EventRef, void *); #else static void GeneralKey(EventRecord *, WindowPtr); static void macKeyMenu(EventRecord *, WindowPtr); static void macKeyText(EventRecord *, WindowPtr); static void macClickMessage(EventRecord *, WindowPtr); static void macClickTerm(EventRecord *, WindowPtr); static void macClickMenu(EventRecord *, WindowPtr); static void macClickText(EventRecord *, WindowPtr); static short macDoNull(EventRecord *, WindowPtr); static short macUpdateMessage(EventRecord *, WindowPtr); static short macUpdateMenu(EventRecord *, WindowPtr); static short GeneralUpdate(EventRecord *, WindowPtr); static void macCursorTerm(EventRecord *, WindowPtr, RgnHandle); static void GeneralCursor(EventRecord *, WindowPtr, RgnHandle); #endif static void TextUpdate(NhWindow *wind); NhWindow *theWindows = (NhWindow *) 0; Cursor qdarrow; /* Borrowed from the Mac tty port */ extern WindowPtr _mt_window; /* Some useful #defines for the scroll bar width and height */ #define SBARWIDTH 15 #define SBARHEIGHT 15 /* * We put a TE on the message window for the "top line" queries. * top_line is the TE that holds both the query and the user's * response. The first topl_query_len characters in top_line are * the query, the rests are the response. topl_resp is the valid * response to a yn query, while topl_resp[topl_def_idx] is the * default response to a yn query. */ static TEHandle top_line = (TEHandle) nil; static int topl_query_len; static int topl_def_idx = -1; static char topl_resp[10] = ""; #define CHAR_ANY '\n' /* * inSelect means we have a menu window up for selection or * something similar. It makes the window with win number == * inSelect a movable modal (unfortunately without the border) * and clicking the close box forces an RET into the key * buffer. Don't forget to set inSelect to WIN_ERR when you're * done... */ static winid inSelect = WIN_ERR; /* * The key queue ring buffer where Read is where to take from, * Write is where next char goes and count is queue depth. */ static unsigned char keyQueue[QUEUE_LEN]; static int keyQueueRead = 0, keyQueueWrite = 0, keyQueueCount = 0; static Boolean gClickedToMove = 0; /* For ObscureCursor */ static Point clicked_pos; /* For nh_poskey */ static int clicked_mod; static Boolean cursor_locked = false; static ControlActionUPP MoveScrollUPP; /* scrolling callback, init'ed in InitMac */ void lock_mouse_cursor(Boolean new_cursor_locked) { cursor_locked = new_cursor_locked; } /* * Add key to input queue, force means flush left and replace if full */ void AddToKeyQueue(unsigned char ch, Boolean force) { if (keyQueueCount < QUEUE_LEN) { keyQueue[keyQueueWrite++] = ch; keyQueueCount++; } else if (force) { keyQueue[keyQueueWrite++] = ch; keyQueueRead++; if (keyQueueRead >= QUEUE_LEN) keyQueueRead = 0; keyQueueCount = QUEUE_LEN; } if (keyQueueWrite >= QUEUE_LEN) keyQueueWrite = 0; } /* * Get key from queue */ unsigned char GetFromKeyQueue(void) { unsigned char ret; if (keyQueueCount) { ret = keyQueue[keyQueueRead++]; keyQueueCount--; if (keyQueueRead >= QUEUE_LEN) keyQueueRead = 0; } else ret = 0; return ret; } /* * Cursor movement */ static RgnHandle gMouseRgn = (RgnHandle) 0; /* * _Gestalt madness - we rely heavily on the _Gestalt glue, since we * don't check for the trap... */ MacFlags macFlags; /* * The screen layouts on the small 512x342 screen need special cares. */ Boolean small_screen = 0; #ifdef NHW_BASE #undef NHW_BASE #endif #define NHW_BASE 0 static int filter_scroll_key(const int, NhWindow *); #if 1 //!TARGET_API_MAC_CARBON static void DoScrollBar(Point, short, ControlHandle, NhWindow *); #endif static pascal void MoveScrollBar(ControlHandle, short); #if 1 //!TARGET_API_MAC_CARBON typedef void (*CbFunc)(EventRecord *, WindowPtr); typedef short (*CbUpFunc)(EventRecord *, WindowPtr); typedef void (*CbCursFunc)(EventRecord *, WindowPtr, RgnHandle); #define NUM_FUNCS 6 static const CbFunc winKeyFuncs[NUM_FUNCS] = { GeneralKey, GeneralKey, GeneralKey, GeneralKey, macKeyMenu, macKeyText }; static const CbFunc winClickFuncs[NUM_FUNCS] = { (CbFunc) macDoNull, macClickMessage, macClickTerm, macClickTerm, macClickMenu, macClickText }; static const CbUpFunc winUpdateFuncs[NUM_FUNCS] = { macDoNull, macUpdateMessage, image_tty, image_tty, macUpdateMenu, GeneralUpdate }; static const CbCursFunc winCursorFuncs[NUM_FUNCS] = { (CbCursFunc) macDoNull, GeneralCursor, macCursorTerm, macCursorTerm, GeneralCursor, GeneralCursor }; #endif static NhWindow * GetNhWin(WindowPtr mac_win) { if (mac_win == _mt_window) /* term window is still maintained by both systems, and */ return theWindows; /* WRefCon still refers to tty struct, so we have to map it */ else { NhWindow *aWin = (NhWindow *) GetWRefCon(mac_win); if (aWin >= theWindows && aWin < &theWindows[NUM_MACWINDOWS]) return aWin; } return ((NhWindow *) nil); } Boolean CheckNhWin(WindowPtr mac_win) { return GetNhWin(mac_win) != nil; } static pascal OSErr AppleEventHandler(const AppleEvent *inAppleEvent, AppleEvent *outAEReply, long inRefCon) { #if defined(__SC__) || defined(__MRC__) #pragma unused(outAEReply, inRefCon) #endif Size actualSize; DescType typeCode; AEEventID EventID; OSErr err; /* Get Event ID */ err = AEGetAttributePtr(inAppleEvent, keyEventIDAttr, typeType, &typeCode, &EventID, sizeof(EventID), &actualSize); if (err == noErr) { switch (EventID) { default: case kAEOpenApplication: macFlags.gotOpen = 1; /* fall through */ case kAEPrintDocuments: err = errAEEventNotHandled; break; case kAEQuitApplication: /* Flush key queue */ keyQueueCount = keyQueueWrite = keyQueueRead = 0; AddToKeyQueue('S', 1); break; case kAEOpenDocuments: { FSSpec fss; FInfo fndrInfo; AEKeyword keywd; AEDescList docList; long index, itemsInList; if ((err = AEGetParamDesc(inAppleEvent, keyDirectObject, typeAEList, &docList)) != noErr || (err = AECountItems(&docList, &itemsInList)) != noErr) { if (err == errAEDescNotFound) itemsInList = 0; else break; } for (index = 1; index <= itemsInList; index++) { err = AEGetNthPtr(&docList, index, typeFSS, &keywd, &typeCode, (Ptr) &fss, sizeof(FSSpec), &actualSize); if (noErr != err) break; err = FSpGetFInfo(&fss, &fndrInfo); if (noErr != err) break; if (fndrInfo.fdType != SAVE_TYPE) continue; /* only look at save files */ process_openfile(fss.vRefNum, fss.parID, fss.name, fndrInfo.fdType); if (macFlags.gotOpen) break; /* got our save file */ } err = AEDisposeDesc(&docList); break; } } } /* Check to see if all required parameters for this type of event are * present */ if (err == noErr) { err = AEGetAttributePtr(inAppleEvent, keyMissedKeywordAttr, typeWildCard, &typeCode, NULL, 0, &actualSize); if (err == errAEDescNotFound) err = noErr; /* got all the required parameters */ else if (err == noErr) /* missed a required parameter */ err = errAEEventNotHandled; } return err; } short win_fonts[NHW_TEXT + 1]; void InitMac(void) { short i; long l; Str255 volName; #if !TARGET_API_MAC_CARBON if (LMGetDefltStack() < 50 * 1024L) { SetApplLimit((void *) ((long) LMGetCurStackBase() - (50 * 1024L))); } MaxApplZone(); for (i = 0; i < 5; i++) MoreMasters(); InitGraf(&qd.thePort); InitFonts(); InitWindows(); InitMenus(); InitDialogs(0L); TEInit(); #endif memset(&macFlags, 0, sizeof(macFlags)); if (!Gestalt(gestaltOSAttr, &l)) { macFlags.processes = (l & (1 << gestaltLaunchControl)) ? 1 : 0; macFlags.tempMem = (l & (1 << gestaltRealTempMemory)) ? 1 : 0; macFlags.hasDebugger = (l & (1 << gestaltSysDebuggerSupport)) ? 1 : 0; } if (!Gestalt(gestaltQuickdrawVersion, &l)) macFlags.color = (l >= gestalt8BitQD) ? 1 : 0; if (!Gestalt(gestaltFindFolderAttr, &l)) macFlags.folders = (l & (1 << gestaltFindFolderPresent)) ? 1 : 0; if (!Gestalt(gestaltHelpMgrAttr, &l)) macFlags.help = (l & (1 << gestaltHelpMgrPresent)) ? 1 : 0; if (!Gestalt(gestaltFSAttr, &l)) macFlags.fsSpec = (l & (1 << gestaltHasFSSpecCalls)) ? 1 : 0; if (!Gestalt(gestaltFontMgrAttr, &l)) macFlags.trueType = (l & (1 << gestaltOutlineFonts)) ? 1 : 0; if (!Gestalt(gestaltAUXVersion, &l)) macFlags.aux = (l >= 0x200) ? 1 : 0; if (!Gestalt(gestaltAliasMgrAttr, &l)) macFlags.alias = (l & (1 << gestaltAliasMgrPresent)) ? 1 : 0; if (!Gestalt(gestaltStandardFileAttr, &l)) macFlags.standardFile = (l & (1 << gestaltStandardFile58)) ? 1 : 0; gMouseRgn = NewRgn(); InitCursor(); GetQDGlobalsArrow(&qdarrow); ObscureCursor(); MoveScrollUPP = NewControlActionUPP(MoveScrollBar); /* Set up base fonts for all window types */ GetFNum("\pHackFont", &i); if (i == 0) i = kFontIDMonaco; win_fonts[NHW_BASE] = win_fonts[NHW_MAP] = win_fonts[NHW_STATUS] = i; GetFNum("\pPSHackFont", &i); if (i == 0) i = kFontIDGeneva; win_fonts[NHW_MESSAGE] = i; win_fonts[NHW_TEXT] = kFontIDGeneva; macFlags.hasAE = 0; if (!Gestalt(gestaltAppleEventsAttr, &l) && (l & (1L << gestaltAppleEventsPresent))) { if (AEInstallEventHandler(kCoreEventClass, typeWildCard, NewAEEventHandlerUPP(AppleEventHandler), 0, FALSE) == noErr) macFlags.hasAE = 1; } #if TARGET_API_MAC_CARBON HGetVol(volName, &theDirs.dataRefNum, &theDirs.dataDirID); #else /* * We should try to get this data from a rsrc, in the profile file * the user double-clicked... This data should be saved with the * save file in the resource fork, AND be saveable in "stationary" */ GetVol(volName, &theDirs.dataRefNum); GetWDInfo(theDirs.dataRefNum, &theDirs.dataRefNum, &theDirs.dataDirID, &l); #endif if (volName[0] > 31) volName[0] = 31; for (l = 1; l <= volName[0]; l++) { if (volName[l] == ':') { volName[l] = 0; volName[0] = l - 1; break; } } BlockMove(volName, theDirs.dataName, l); BlockMove(volName, theDirs.saveName, l); BlockMove(volName, theDirs.levelName, l); theDirs.saveRefNum = theDirs.levelRefNum = theDirs.dataRefNum; theDirs.saveDirID = theDirs.levelDirID = theDirs.dataDirID; /* Create the "record" file, if necessary */ check_recordfile(""); #if 0 // TARGET_API_MAC_CARBON /* Create event handler universal procedure pointers */ dispatcher = GetEventDispatcherTarget(); baseupp = NewEventHandlerUPP(BaseEvent); msgupp = NewEventHandlerUPP(MsgEvent); menwupp = NewEventHandlerUPP(MenwEvent); textupp = NewEventHandlerUPP(TextEvent); InstallApplicationEventHandler(NewEventHandlerUPP(GlobalEvent), sizeof(globalevents)/sizeof(EventTypeSpec), globalevents, NULL, NULL); #endif return; } /* * Change default window fonts. */ short set_tty_font_name(int window_type, char *font_name) { short fnum; Str255 new_font; if (window_type < NHW_BASE || window_type > NHW_TEXT) return general_failure; C2P(font_name, new_font); GetFNum(new_font, &(fnum)); if (!fnum) return general_failure; win_fonts[window_type] = fnum; return noErr; } static void DrawScrollbar(NhWindow *aWin) { WindowPtr theWindow = aWin->its_window; Rect crect, wrect; Boolean vis; short val, lin, win_height; if (!aWin->scrollBar) return; GetControlBounds(aWin->scrollBar, &crect); GetWindowBounds(aWin->its_window, kWindowContentRgn, &wrect); OffsetRect(&wrect, -wrect.left, -wrect.top); win_height = wrect.bottom - wrect.top; if (crect.top != wrect.top - 1 || crect.left != wrect.right - SBARWIDTH) { MoveControl(aWin->scrollBar, wrect.right - SBARWIDTH, wrect.top - 1); } if (crect.bottom != wrect.bottom - SBARHEIGHT || crect.right != wrect.right + 1) { SizeControl(aWin->scrollBar, SBARWIDTH + 1, win_height - SBARHEIGHT + 2); } vis = (win_height > (50 + SBARHEIGHT)); if (vis != IsControlVisible(aWin->scrollBar)) { /* current status != control */ if (vis) /* if visible, show */ ShowControl(aWin->scrollBar); else /* else hide */ HideControl(aWin->scrollBar); } lin = aWin->y_size; if (aWin == theWindows + WIN_MESSAGE) { /* calculate how big scroll bar is for message window */ lin -= (win_height - SBARHEIGHT) / aWin->row_height; if (lin < 0) lin = 0; val = 0; /* always have message scrollbar active */ } else { /* calculate how big scroll bar is for other windows */ lin -= win_height / aWin->row_height; if (lin < 0) lin = 0; if (lin) val = 0; /* if there are 1+ screen lines, activate scrollbar */ else val = 255; /* else grey it out */ } SetControlMaximum(aWin->scrollBar, lin); HiliteControl(aWin->scrollBar, val); val = GetControlValue(aWin->scrollBar); if (val != aWin->scrollPos) { InvalWindowRect(theWindow, &wrect); aWin->scrollPos = val; } } #define MAX_HEIGHT 100 #define MIN_HEIGHT 50 #define MIN_WIDTH 300 /* * This function could be overloaded with any amount of intelligence... */ int SanePositions(void) { #if TARGET_API_MAC_CARBON Rect rbase, rmsg; SInt16 i, width, height; ConstrainWindowToScreen(_mt_window, kWindowContentRgn, kWindowConstrainMoveRegardlessOfFit, NULL, NULL); GetWindowBounds(_mt_window, kWindowContentRgn, &rbase); if (RetrievePosition(kMapWindow, &rbase.top, &rbase.left)) MoveWindow(_mt_window, rbase.left, rbase.top, TRUE); GetWindowBounds(theWindows[NHW_MESSAGE].its_window, kWindowContentRgn, &rmsg); height = rmsg.bottom - rmsg.top; rmsg.top = rbase.bottom + 2; rmsg.bottom = rmsg.top + height; rmsg.left = rbase.left; rmsgr.right = rbase.right; RetrievePosition(kMessageWindow, &rmsg.top, &rmsg.left); if (RetrieveSize(kMessageWindow, rmsg.top, rmsg.left, &height, &width)) { rmsgr.right = rmsg.left + width; rmsg.bottom = rmsg.top + height; } SetWindowBounds(theWindows[NHW_MESSAGE].its_window, kWindowContentRgn, &rmsg); ConstrainWindowToScreen(theWindows[NHW_MESSAGE].its_window, kWindowContentRgn, kWindowConstrainMoveRegardlessOfFit, NULL, NULL); DrawScrollbar(&theWindows[NHW_MESSAGE]); for (i = 0; i < NUM_MACWINDOWS; i++) if (i != WIN_STATUS && i != WIN_MESSAGE && i != WIN_MAP && i != BASE_WINDOW && theWindows[i].its_window) { /* FIXME */ ConstrainWindowToScreen( theWindows[i].its_window, kWindowContentRgn, kWindowConstrainMoveRegardlessOfFit, NULL, NULL); } #else short left, top, width, height; int ix, numText = 0, numMenu = 0; int mbar_height = GetMBarHeight(); BitMap qbitmap; Rect screenArea; WindowPtr theWindow; NhWindow *nhWin; screenArea = GetQDGlobalsScreenBits(&qbitmap)->bounds; OffsetRect(&screenArea, -screenArea.left, -screenArea.top); /* Map Window */ height = _mt_window->portRect.bottom - _mt_window->portRect.top; width = _mt_window->portRect.right - _mt_window->portRect.left; if (!RetrievePosition(kMapWindow, &top, &left)) { top = mbar_height + (small_screen ? 2 : 20); left = (screenArea.right - width) / 2; } MoveWindow(_mt_window, left, top, 1); /* Message Window */ if (!RetrievePosition(kMessageWindow, &top, &left)) { top += height; if (!small_screen) top += 20; } if (!RetrieveSize(kMessageWindow, top, left, &height, &width)) { height = screenArea.bottom - top - (small_screen ? 2 - SBARHEIGHT : 2); if (height > MAX_HEIGHT) { height = MAX_HEIGHT; } else if (height < MIN_HEIGHT) { height = MIN_HEIGHT; width = MIN_WIDTH; left = screenArea.right - width; top = screenArea.bottom - MIN_HEIGHT; } } /* Move these windows */ nhWin = theWindows + WIN_MESSAGE; theWindow = nhWin->its_window; MoveWindow(theWindow, left, top, 1); SizeWindow(theWindow, width, height, 1); if (nhWin->scrollBar) DrawScrollbar(nhWin); /* Handle other windows */ for (ix = 0; ix < NUM_MACWINDOWS; ix++) { if (ix != WIN_STATUS && ix != WIN_MESSAGE && ix != WIN_MAP && ix != BASE_WINDOW) { theWindow = theWindows[ix].its_window; if (theWindow && ((WindowPeek) theWindow)->visible) { int shift; if (((WindowPeek) theWindow)->windowKind == WIN_BASE_KIND + NHW_MENU) { if (!RetrievePosition(kMenuWindow, &top, &left)) { top = mbar_height * 2; left = 2; } top += (numMenu * mbar_height); numMenu++; shift = 20; } else { if (!RetrievePosition(kTextWindow, &top, &left)) { top = mbar_height * 2; left = screenArea.right - 3 - (theWindow->portRect.right - theWindow->portRect.left); } top += (numText * mbar_height); numText++; shift = -20; } while (top > screenArea.bottom - MIN_HEIGHT) { top -= screenArea.bottom - mbar_height * 2; left += shift; } MoveWindow(theWindow, left, top, 1); } } } #endif return (0); } void mac_init_nhwindows(int *argcp, char **argv) { Rect r; #if !TARGET_API_MAC_CARBON Rect scr = (*GetGrayRgn())->rgnBBox; small_screen = scr.bottom - scr.top <= (iflags.large_font ? 12 * 40 : 9 * 40); #endif InitMenuRes(); theWindows = (NhWindow *) NewPtrClear(NUM_MACWINDOWS * sizeof(NhWindow)); if (MemError()) error("mac_init_nhwindows: Couldn't allocate memory for windows."); DimMenuBar(); tty_init_nhwindows(argcp, argv); iflags.window_inited = TRUE; /* Some ugly hacks to make both interfaces happy: * Mac port uses both tty interface (for main map) and extra windows. The * winids need to * be kept in synch for both interfaces to map. Also, the "blocked" * display_nhwindow case * for the map automatically calls the tty interface for the message box, * so some version * of the message box has to exist in the tty world to prevent a meltdown, * even though most * messages are handled in mac window. */ mac_create_nhwindow(NHW_BASE); tty_create_nhwindow(NHW_MESSAGE); #if 1 //!TARGET_API_MAC_CARBON /* Resize and reposition the message window */ RetrievePosition(kMessageWindow, &r.top, &r.left); RetrieveSize(kMessageWindow, r.top, r.left, &r.bottom, &r.right); MoveWindow(theWindows[NHW_MESSAGE].its_window, r.left, r.top, false); SizeWindow(theWindows[NHW_MESSAGE].its_window, r.right, r.bottom, true); #endif return; } winid mac_create_nhwindow(int kind) { int i; NhWindow *aWin; FontInfo fi; if (kind < NHW_BASE || kind > NHW_TEXT) { error("cre_win: Invalid kind %d.", kind); return WIN_ERR; } for (i = 0; i < NUM_MACWINDOWS; i++) { if (!theWindows[i].its_window) break; } if (i >= NUM_MACWINDOWS) { error("cre_win: Win full; freeing extras"); for (i = 0; i < NUM_MACWINDOWS; i++) { if (IsWindowVisible(theWindows[i].its_window) || i == WIN_INVEN || GetWindowKind(theWindows[i].its_window) != WIN_BASE_KIND + NHW_MENU && GetWindowKind(theWindows[i].its_window) != WIN_BASE_KIND + NHW_TEXT) continue; mac_destroy_nhwindow(i); goto got1; } error("cre_win: Out of ids!"); return WIN_ERR; } got1: aWin = &theWindows[i]; aWin->windowTextLen = 0L; aWin->scrollBar = (ControlHandle) 0; aWin->menuInfo = 0; aWin->menuSelected = 0; aWin->miLen = 0; aWin->miSize = 0; aWin->menuChar = 'a'; dprintf("cre_win: New kind %d", kind); if (kind == NHW_BASE || kind == NHW_MAP || kind == NHW_STATUS) { short x_sz, x_sz_p, y_sz, y_sz_p; if (kind != NHW_BASE) { if (i != tty_create_nhwindow(kind)) { dprintf("cre_win: error creating kind %d", kind); } if (kind == NHW_MAP) { wins[i]->offy = 0; /* the message box is in a separate window */ } } aWin->its_window = _mt_window; get_tty_metrics(aWin->its_window, &x_sz, &y_sz, &x_sz_p, &y_sz_p, &aWin->font_number, &aWin->font_size, &aWin->char_width, &aWin->row_height); #if 0 // TARGET_API_MAC_CARBON InstallWindowEventHandler(aWin->its_window, baseupp, sizeof(baseevents)/sizeof(EventTypeSpec), baseevents, (void *)aWin, NULL); #endif return i; } aWin->its_window = GetNewWindow(WIN_BASE_RES + kind, (WindowPtr) 0L, (WindowPtr) -1L); SetWindowKind(aWin->its_window, WIN_BASE_KIND + kind); SetWRefCon(aWin->its_window, (long) aWin); if (!(aWin->windowText = NewHandle(TEXT_BLOCK))) { error("cre_win: NewHandle fail(%ld)", (long) TEXT_BLOCK); DisposeWindow(aWin->its_window); aWin->its_window = (WindowPtr) 0; return WIN_ERR; } aWin->x_size = aWin->y_size = 0; aWin->x_curs = aWin->y_curs = 0; aWin->drawn = TRUE; mac_clear_nhwindow(i); #if 0 // TARGET_API_MAC_CARBON switch (kind) { case NHW_MESSAGE: InstallWindowEventHandler(aWin->its_window, msgupp, sizeof(msgevents)/sizeof(EventTypeSpec), msgevents, (void *)aWin, NULL); break; case NHW_MENU: InstallWindowEventHandler(aWin->its_window, menwupp, sizeof(menwevents)/sizeof(EventTypeSpec), menwevents, (void *)aWin, NULL); break; case NHW_TEXT: InstallWindowEventHandler(aWin->its_window, textupp, sizeof(textevents)/sizeof(EventTypeSpec), textevents, (void *)aWin, NULL); break; } #endif SetPortWindowPort(aWin->its_window); if (kind == NHW_MESSAGE) { aWin->font_number = win_fonts[NHW_MESSAGE]; aWin->font_size = iflags.wc_fontsiz_message ? iflags.wc_fontsiz_message : iflags.large_font ? 12 : 9; if (!top_line) { const Rect out_of_scr = { 10000, 10000, 10100, 10100 }; TextFont(aWin->font_number); TextSize(aWin->font_size); TextFace(bold); top_line = TENew(&out_of_scr, &out_of_scr); TEActivate(top_line); TextFace(normal); } } else { aWin->font_number = win_fonts[NHW_TEXT]; aWin->font_size = iflags.wc_fontsiz_text ? iflags.wc_fontsiz_text : 9; } TextFont(aWin->font_number); TextSize(aWin->font_size); GetFontInfo(&fi); aWin->ascent_height = fi.ascent + fi.leading; aWin->row_height = aWin->ascent_height + fi.descent; aWin->char_width = fi.widMax; if (kind == NHW_MENU || kind == NHW_TEXT || kind == NHW_MESSAGE) { Rect r; GetWindowBounds(aWin->its_window, kWindowContentRgn, &r); r.right -= (r.left - 1); r.left = r.right - SBARWIDTH; r.bottom -= (r.top + SBARHEIGHT); r.top = -1; aWin->scrollBar = NewControl(aWin->its_window, &r, "\p", (r.bottom > r.top + 50), 0, 0, 0, 16, 0L); aWin->scrollPos = 0; } return i; } void mac_clear_nhwindow(winid win) { long l; Rect r; NhWindow *aWin = &theWindows[win]; WindowPtr theWindow = aWin->its_window; if (win < 0 || win >= NUM_MACWINDOWS || !theWindow) { error("clr_win: Invalid win %d.", win); return; } if (theWindow == _mt_window) { tty_clear_nhwindow(win); return; } if (!aWin->drawn) return; SetPortWindowPort(theWindow); GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); if (aWin->scrollBar) r.right -= SBARWIDTH; switch (GetWindowKind(theWindow) - WIN_BASE_KIND) { case NHW_MESSAGE: if (aWin->scrollPos == aWin->y_size - 1) /* if no change since last clear */ return; /* don't bother with redraw */ r.bottom -= SBARHEIGHT; for (l = 0; aWin->y_size > iflags.msg_history;) { const char cr = CHAR_CR; l = Munger(aWin->windowText, l, &cr, 1, nil, 0) + 1; --aWin->y_size; } if (l) { aWin->windowTextLen -= l; BlockMove(*aWin->windowText + l, *aWin->windowText, aWin->windowTextLen); } aWin->last_more_lin = aWin->y_size; aWin->save_lin = aWin->y_size; aWin->scrollPos = aWin->y_size ? aWin->y_size - 1 : 0; break; case NHW_MENU: if (aWin->menuInfo) { DisposeHandle((Handle) aWin->menuInfo); aWin->menuInfo = NULL; } if (aWin->menuSelected) { DisposeHandle((Handle) aWin->menuSelected); aWin->menuSelected = NULL; } aWin->menuChar = 'a'; aWin->miSelLen = 0; aWin->miLen = 0; aWin->miSize = 0; /* Fall-Through */ default: SetHandleSize(aWin->windowText, TEXT_BLOCK); aWin->windowTextLen = 0L; aWin->x_size = 0; aWin->y_size = 0; aWin->scrollPos = 0; break; } if (aWin->scrollBar) { SetControlMaximum(aWin->scrollBar, aWin->y_size); SetControlValue(aWin->scrollBar, aWin->scrollPos); } aWin->y_curs = 0; aWin->x_curs = 0; aWin->drawn = FALSE; InvalWindowRect(theWindow, &r); } static Boolean ClosingWindowChar(const int c) { return (c == CHAR_ESC || c == CHAR_BLANK || c == CHAR_LF || c == CHAR_CR); } static Boolean in_topl_mode(void) { Rect rect; GetWindowBounds(theWindows[WIN_MESSAGE].its_window, kWindowContentRgn, &rect); OffsetRect(&rect, -rect.left, -rect.top); return (WIN_MESSAGE != WIN_ERR && top_line && (*top_line)->viewRect.left < rect.right); } #define BTN_IND 2 #define BTN_W 40 #define BTN_H (SBARHEIGHT - 3) static void topl_resp_rect(int resp_idx, Rect *r) { Rect rect; GetWindowBounds(theWindows[WIN_MESSAGE].its_window, kWindowContentRgn, &rect); OffsetRect(&rect, -rect.left, -rect.top); r->left = (BTN_IND + BTN_W) * resp_idx + BTN_IND; r->right = r->left + BTN_W; r->bottom = rect.bottom - 1; r->top = r->bottom - BTN_H; return; } void enter_topl_mode(char *query) { if (in_topl_mode()) return; putstr(WIN_MESSAGE, ATR_BOLD, query); topl_query_len = strlen(query); (*top_line)->selStart = topl_query_len; (*top_line)->selEnd = topl_query_len; (*top_line)->viewRect.left = 0; PtrToXHand(query, (*top_line)->hText, topl_query_len); TECalText(top_line); DimMenuBar(); mac_display_nhwindow(WIN_MESSAGE, FALSE); } void leave_topl_mode(char *answer) { /*unsigned*/ char *ap, *bp; int ans_len = (*top_line)->teLength - topl_query_len; NhWindow *aWin = theWindows + WIN_MESSAGE; if (!in_topl_mode()) return; /* Cap length of reply */ if (ans_len >= BUFSZ) ans_len = BUFSZ - 1; /* remove unprintables from the answer */ for (ap = *(*top_line)->hText + topl_query_len, bp = answer; ans_len > 0; ans_len--, ap++) { if (*ap >= ' ' && *ap < 128) { *bp++ = *ap; } } *bp = 0; if (aWin->windowTextLen && (*aWin->windowText)[aWin->windowTextLen - 1] == CHAR_CR) { --aWin->windowTextLen; --aWin->y_size; } putstr(WIN_MESSAGE, ATR_BOLD, answer); (*top_line)->viewRect.left += 10000; UndimMenuBar(); } /* * TESetSelect flushes out all the pending key strokes. I hate it. */ static void topl_set_select(short selStart, short selEnd) { TEDeactivate(top_line); (*top_line)->selStart = selStart; (*top_line)->selEnd = selEnd; TEActivate(top_line); } static void topl_replace(char *new_ans) { topl_set_select(topl_query_len, (*top_line)->teLength); TEDelete(top_line); TEInsert(new_ans, strlen(new_ans), top_line); } Boolean topl_key(unsigned char ch, Boolean ext) { switch (ch) { case CHAR_ESC: topl_replace("\x1b"); case CHAR_ENTER: case CHAR_CR: case CHAR_LF: return false; case 0x1f & 'P': mac_doprev_message(); return true; case '\x1e' /* up arrow */: topl_replace(""); return true; case CHAR_BS: case '\x1c' /* left arrow */: if ((*top_line)->selEnd <= topl_query_len) return true; else if (ext) { topl_replace(""); return true; } default: TEKey(ch, top_line); if (ext) { int com_index = -1, oindex = 0; while (extcmdlist[oindex].ef_txt != (char *) 0) { if (!strncmpi(*(*top_line)->hText + topl_query_len, extcmdlist[oindex].ef_txt, (*top_line)->teLength - topl_query_len)) { if (com_index == -1) /* No matches yet*/ com_index = oindex; else /* More than 1 match */ { com_index = -2; break; } } oindex++; } if (com_index >= 0) topl_replace((char *) extcmdlist[com_index].ef_txt); } return true; } } static void topl_flash_resp(int resp_idx) { unsigned long dont_care; Rect frame; SetPortWindowPort(theWindows[WIN_MESSAGE].its_window); topl_resp_rect(resp_idx, &frame); InsetRect(&frame, 1, 1); InvertRect(&frame); Delay(GetDblTime() / 2, &dont_care); InvertRect(&frame); } static void topl_set_def(int new_def_idx) { Rect frame; SetPortWindowPort(theWindows[WIN_MESSAGE].its_window); topl_resp_rect(topl_def_idx, &frame); InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame); topl_def_idx = new_def_idx; topl_resp_rect(new_def_idx, &frame); InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame); } void topl_set_resp(char *resp, char def) { char *loc; Rect frame; int r_len, r_len1; if (!resp) { const char any_str[2] = { CHAR_ANY, '\0' }; resp = (char *) any_str; def = CHAR_ANY; } SetPortWindowPort(theWindows[WIN_MESSAGE].its_window); r_len1 = strlen(resp); r_len = strlen(topl_resp); if (r_len < r_len1) r_len = r_len1; topl_resp_rect(0, &frame); frame.right = (BTN_IND + BTN_W) * r_len; InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame); strcpy(topl_resp, resp); loc = strchr(resp, def); topl_def_idx = loc ? loc - resp : -1; } static char topl_resp_key(char ch) { if (strlen(topl_resp) > 0) { char *loc = strchr(topl_resp, ch); if (!loc) { if (ch == '\x9' /* tab */) { topl_set_def(topl_def_idx <= 0 ? strlen(topl_resp) - 1 : topl_def_idx - 1); ch = '\0'; } else if (ch == CHAR_ESC) { loc = strchr(topl_resp, 'q'); if (!loc) { loc = strchr(topl_resp, 'n'); if (!loc && topl_def_idx >= 0) loc = topl_resp + topl_def_idx; } } else if (ch == (0x1f & 'P')) { mac_doprev_message(); ch = '\0'; } else if (topl_def_idx >= 0) { if (ch == CHAR_ENTER || ch == CHAR_CR || ch == CHAR_LF || ch == CHAR_BLANK || topl_resp[topl_def_idx] == CHAR_ANY) loc = topl_resp + topl_def_idx; else if (strchr(topl_resp, '#')) { if (digit(ch)) { topl_set_def(strchr(topl_resp, '#') - topl_resp); TEKey(ch, top_line); ch = '\0'; } else if (topl_resp[topl_def_idx] == '#') { if (ch == '\x1e' /* up arrow */) { topl_set_select(topl_query_len, topl_query_len); ch = '\0'; } else if (ch == '\x1d' /* right arrow */ || ch == '\x1f' /* down arrow */ || ch == CHAR_BS || ch == '\x1c' /* left arrow */ && (*top_line)->selEnd > topl_query_len) { TEKey(ch, top_line); ch = '\0'; } } } } } if (loc) { topl_flash_resp(loc - topl_resp); if (*loc != CHAR_ANY) ch = *loc; TEKey(ch, top_line); } } return ch; } static void adjust_window_pos(NhWindow *aWin, short width, short height) { WindowRef theWindow = aWin->its_window; #if TARGET_API_MAC_CARBON Rect r; GetWindowBounds(theWindow, kWindowContentRgn, &r); RetrieveWinPos(theWindow, &r.top, &r.left); MoveWindow(theWindow, r.left, r.top, false); SizeWindow(theWindow, width, height, true); ConstrainWindowToScreen(theWindow, kWindowStructureRgn, kWindowConstrainMayResize | kWindowConstrainMoveRegardlessOfFit, NULL, NULL); #else Rect scr_r = (*GetGrayRgn())->rgnBBox; const Rect win_ind = { 2, 2, 3, 3 }; const short min_w = theWindow->portRect.right - theWindow->portRect.left, max_w = scr_r.right - scr_r.left - win_ind.left - win_ind.right; Point pos; short max_h; SetPortWindowPort(theWindow); if (!RetrieveWinPos(theWindow, &pos.v, &pos.h)) { pos.v = 0; /* take window's existing position */ pos.h = 0; LocalToGlobal(&pos); } max_h = scr_r.bottom - win_ind.bottom - pos.v; if (height > max_h) height = max_h; if (height < MIN_HEIGHT) height = MIN_HEIGHT; if (width < min_w) width = min_w; if (width > max_w) width = max_w; SizeWindow(theWindow, width, height, true); if (pos.v + height + win_ind.bottom > scr_r.bottom) pos.v = scr_r.bottom - height - win_ind.bottom; if (pos.h + width + win_ind.right > scr_r.right) pos.h = scr_r.right - width - win_ind.right; MoveWindow(theWindow, pos.h, pos.v, false); #endif if (aWin->scrollBar) DrawScrollbar(aWin); return; } /* * display/select/update the window. * If f is true, this window should be "modal" - don't return * until presumed seen. */ void mac_display_nhwindow(winid win, BOOLEAN_P f) { NhWindow *aWin = &theWindows[win]; WindowPtr theWindow = aWin->its_window; if (win < 0 || win >= NUM_MACWINDOWS || !theWindow) { error("disp_win: Invalid window %d.", win); return; } if (theWindow == _mt_window) { tty_display_nhwindow(win, f); return; } if (f && inSelect == WIN_ERR && win == WIN_MESSAGE) { topl_set_resp((char *) 0, 0); if (aWin->windowTextLen > 0 && (*aWin->windowText)[aWin->windowTextLen - 1] == CHAR_CR) { --aWin->windowTextLen; --aWin->y_size; } putstr(win, flags.standout ? ATR_INVERSE : ATR_NONE, " --More--"); } if (!IsWindowVisible(theWindow)) { if (win != WIN_MESSAGE) adjust_window_pos(aWin, aWin->x_size + SBARWIDTH + 1, aWin->y_size * aWin->row_height); SelectWindow(theWindow); ShowWindow(theWindow); } if (f && inSelect == WIN_ERR) { int ch; DimMenuBar(); inSelect = win; do { ch = mac_nhgetch(); } while (!ClosingWindowChar(ch)); inSelect = WIN_ERR; UndimMenuBar(); if (win == WIN_MESSAGE) topl_set_resp("", '\0'); else HideWindow(theWindow); } } void mac_destroy_nhwindow(winid win) { WindowPtr theWindow; NhWindow *aWin = &theWindows[win]; int kind; if (win < 0 || win >= NUM_MACWINDOWS) { if (iflags.window_inited) error("dest_win: Invalid win %d.", win); return; } theWindow = aWin->its_window; if (!theWindow) { error("dest_win: Not allocated win %d.", win); return; } /* * Check special windows. The base window should never go away. * Other "standard" windows should not go away unless we've exitted * nhwindows. */ if (theWindow == _mt_window) { return; } if (win == WIN_INVEN || win == WIN_MESSAGE) { if (iflags.window_inited) { if (flags.tombstone && killer[0]) { /* Prepare for the coming of the tombstone window. */ win_fonts[NHW_TEXT] = kFontIDMonaco; } return; } if (win == WIN_MESSAGE) WIN_MESSAGE = WIN_ERR; } kind = GetWindowKind(theWindow) - WIN_BASE_KIND; if ((!IsWindowVisible(theWindow) || (kind != NHW_MENU && kind != NHW_TEXT))) { DisposeWindow(theWindow); if (aWin->windowText) { DisposeHandle(aWin->windowText); } aWin->its_window = (WindowPtr) 0; aWin->windowText = (Handle) 0; } } void mac_number_pad(int pad) { /* no effect */ #if defined(__SC__) || defined(__MRC__) #pragma unused(pad) #endif return; } void trans_num_keys(EventRecord *theEvent) { #if defined(__SC__) || defined(__MRC__) #pragma unused(theEvent) #endif /* KMH -- Removed this translation. * Number pad keys should always emit digit characters. * That's consistent with the default MacOS behavior. * The number_pad option controls how digits are interpreted. */ #if 0 if (Cmd.num_pad) { Handle h = GetResource('Nump', theEvent->modifiers & shiftKey ? 129 : 128); if (h) { short inkey = (theEvent->message & keyCodeMask), *ab = (short *)*h; int i = ab[0]; for (; i; i--) { if (inkey == (ab[i] & keyCodeMask)) { theEvent->message = ab[i]; break; } } } } #endif } /* * Routine used to select and de-select elements in a menu window, used by * KeyMenu, * ClickMenu, and UpdateMenu. Takes the NhWindow and a line ref relative to * the scrollbar. */ static void ToggleMenuSelect(NhWindow *aWin, int line) { Rect r; GetWindowBounds(aWin->its_window, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); if (aWin->scrollBar) r.right -= SBARWIDTH; r.top = line * aWin->row_height; r.bottom = r.top + aWin->row_height; LMSetHiliteMode((UInt8)(LMGetHiliteMode() & 0x7F)); InvertRect(&r); } /* * Check to see if given item is selected, return index if it is */ static int ListItemSelected(NhWindow *aWin, int item) { int i; HLock((char **) aWin->menuSelected); /* Find item in selection list */ for (i = aWin->miSelLen - 1; i >= 0; i--) { if ((*aWin->menuSelected)[i] == item) break; } HUnlock((char **) aWin->menuSelected); return i; } /* * Add item to selection list if it's not selected already * If it is selected already, remove it from the list. */ static void ToggleMenuListItemSelected(NhWindow *aWin, short item) { int i = ListItemSelected(aWin, item); HLock((char **) aWin->menuSelected); if (i < 0) { /* not there, so add */ (*aWin->menuSelected)[aWin->miSelLen] = item; aWin->miSelLen++; } else { /* there, so remove */ short *mi = &(*aWin->menuSelected)[i]; aWin->miSelLen--; memcpy(mi, mi + 1, (aWin->miSelLen - i) * sizeof(short)); } HUnlock((char **) aWin->menuSelected); } /* * Find menu item in list given a line number on the window */ static short ListCoordinateToItem(NhWindow *aWin, short Row) { int i, item = -1; MacMHMenuItem *mi; HLock((char **) aWin->menuInfo); for (i = 0, mi = *aWin->menuInfo; i < aWin->miLen; i++, mi++) { if (mi->line == Row + aWin->scrollPos) { item = i; break; } } HUnlock((char **) aWin->menuInfo); return item; } static pascal void MoveScrollBar(ControlHandle theBar, short part) { #if 1 //!TARGET_API_MAC_CARBON EventRecord fake; #endif Rect r; RgnHandle rgn; int now, amtToScroll; WindowPtr theWin; NhWindow *winToScroll; if (!part) return; theWin = GetControlOwner(theBar); GetWindowBounds(theWin, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); winToScroll = (NhWindow *) (GetWRefCon(theWin)); now = GetControlValue(theBar); if (part == kControlPageUpPart || part == kControlPageDownPart) amtToScroll = (r.bottom - r.top) / winToScroll->row_height; else amtToScroll = 1; if (part == kControlPageUpPart || part == kControlUpButtonPart) { int bound = GetControlMinimum(theBar); if (now - bound < amtToScroll) amtToScroll = now - bound; amtToScroll = -amtToScroll; } else { int bound = GetControlMaximum(theBar); if (bound - now < amtToScroll) amtToScroll = bound - now; } if (!amtToScroll) return; SetControlValue(theBar, now + amtToScroll); winToScroll->scrollPos = now + amtToScroll; r.right -= SBARWIDTH; if (winToScroll == theWindows + WIN_MESSAGE) r.bottom -= SBARHEIGHT; rgn = NewRgn(); ScrollRect(&r, 0, -amtToScroll * winToScroll->row_height, rgn); if (rgn) { InvalWindowRgn(theWin, rgn); BeginUpdate(theWin); } #if 0 // TARGET_API_MAC_CARBON switch (GetWindowKind(theWin) - WIN_BASE_KIND) { case NHW_MESSAGE: MsgUpdate(GetNhWin(theWin)); break; case NHW_MENU: MenwUpdate(GetNhWin(theWin)); break; case NHW_TEXT: TextUpdate(GetNhWin(theWin)); break; } #else winUpdateFuncs[GetWindowKind(theWin) - WIN_BASE_KIND](&fake, theWin); #endif if (rgn) { EndUpdate(theWin); DisposeRgn(rgn); } } #if 1 //!TARGET_API_MAC_CARBON static void DoScrollBar(Point p, short code, ControlHandle theBar, NhWindow *aWin) { ControlActionUPP func = NULL; Rect rect; if (code == kControlUpButtonPart || code == kControlPageUpPart || code == kControlDownButtonPart || code == kControlPageDownPart) func = MoveScrollUPP; (void) TrackControl(theBar, p, func); if (!func) { if (aWin->scrollPos != GetControlValue(theBar)) { aWin->scrollPos = GetControlValue(theBar); GetWindowBounds(aWin->its_window, kWindowContentRgn, &rect); OffsetRect(&rect, -rect.left, -rect.top); InvalWindowRect(aWin->its_window, &rect); } } } #endif static int filter_scroll_key(const int ch, NhWindow *aWin) { if (aWin->scrollBar && GetControlValue(aWin->scrollBar) < GetControlMaximum(aWin->scrollBar)) { short part = 0; if (ch == CHAR_BLANK) { part = kControlPageDownPart; } else if (ch == CHAR_CR || ch == CHAR_LF) { part = kControlDownButtonPart; } if (part) { SetPortWindowPort(aWin->its_window); MoveScrollBar(aWin->scrollBar, part); return 0; } } return ch; } int mac_doprev_message(void) { if (WIN_MESSAGE) { NhWindow *winToScroll = &theWindows[WIN_MESSAGE]; mac_display_nhwindow(WIN_MESSAGE, FALSE); SetPortWindowPort(winToScroll->its_window); MoveScrollBar(winToScroll->scrollBar, kControlUpButtonPart); } return 0; } static void draw_growicon_vert_only(WindowPtr wind) { GrafPtr org_port; RgnHandle org_clip = NewRgn(); Rect r; GetPort(&org_port); SetPortWindowPort(wind); GetClip(org_clip); GetWindowBounds(wind, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); r.left = r.right - SBARWIDTH; ClipRect(&r); DrawGrowIcon(wind); SetClip(org_clip); DisposeRgn(org_clip); SetPort(org_port); } /* NOT_IN_CARBON */ static void WindowGoAway(EventRecord *theEvent, WindowPtr theWindow) { NhWindow *aWin = GetNhWin(theWindow); if (!theEvent || TrackGoAway(theWindow, theEvent->where)) { if (aWin - theWindows == BASE_WINDOW && !iflags.window_inited) { AddToKeyQueue('\033', 1); } else { HideWindow(theWindow); if (aWin - theWindows != inSelect) mac_destroy_nhwindow(aWin - theWindows); else /* if this IS the inSelect window put a close char */ AddToKeyQueue(CHAR_CR, 1); /* in queue to exit and maintain inSelect */ } } } void mac_get_nh_event(void) { EventRecord anEvent; /* KMH -- Don't proceed if the window system isn't set up */ if (!iflags.window_inited) return; #if TARGET_API_MAC_CARBON QDFlushPortBuffer(GetWindowPort(_mt_window), NULL); #endif (void) WaitNextEvent(everyEvent, &anEvent, 1, gMouseRgn); HandleEvent(&anEvent); return; } int mac_nhgetch(void) { int ch; long doDawdle = 1L; EventRecord anEvent; #if 1 //!TARGET_API_MAC_CARBON /* We want to take care of keys in the buffer as fast as * possible */ if (keyQueueCount) doDawdle = 0L; else { long total, contig; static char warn = 0; doDawdle = (in_topl_mode() ? GetCaretTime() : 120L); /* Since we have time, check memory */ PurgeSpace(&total, &contig); if (contig < 25000L || total < 50000L) { if (!warn) { pline("Low Memory!"); warn = 1; } } else { warn = 0; } } #endif do { #if TARGET_API_MAC_CARBON QDFlushPortBuffer(GetWindowPort(_mt_window), NULL); #endif #if 0 // TARGET_API_MAC_CARBON EventRef event; if (ReceiveNextEvent(0, NULL, kEventDurationForever, TRUE, &event) == noErr) { SendEventToEventTarget(event, dispatcher); ReleaseEvent(event); } #else (void) WaitNextEvent(everyEvent, &anEvent, doDawdle, gMouseRgn); HandleEvent(&anEvent); #endif ch = GetFromKeyQueue(); } while (!ch && !gClickedToMove); if (!gClickedToMove) ObscureCursor(); else gClickedToMove = 0; #ifdef THINK_C if (ch == '\r') ch = '\n'; #endif return (ch); } void mac_delay_output(void) { long destTicks = TickCount() + 1; while (TickCount() < destTicks) { mac_get_nh_event(); } } #ifdef CLIPPING static void mac_cliparound(int x, int y) { #if defined(__SC__) || defined(__MRC__) #pragma unused(x, y) #endif /* TODO */ } #endif void mac_exit_nhwindows(const char *s) { clear_screen(); tty_exit_nhwindows(s); mac_destroy_nhwindow(WIN_MESSAGE); mac_destroy_nhwindow(WIN_INVEN); } /* * Don't forget to decrease in_putstr before returning... */ void mac_putstr(winid win, int attr, const char *str) { long len, slen; NhWindow *aWin = &theWindows[win]; static char in_putstr = 0; short newWidth, maxWidth; Rect r; char *src, *sline, *dst, ch; if (win < 0 || win >= NUM_MACWINDOWS || !aWin->its_window) { error("putstr: Invalid win %d (Max %d).", win, NUM_MACWINDOWS, attr); return; } if (aWin->its_window == _mt_window) { tty_putstr(win, attr, str); return; } if (in_putstr > 3) return; in_putstr++; slen = strlen(str); SetPortWindowPort(aWin->its_window); GetWindowBounds(aWin->its_window, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); if (win == WIN_MESSAGE) { r.right -= SBARWIDTH; r.bottom -= SBARHEIGHT; if (flags.page_wait && aWin->last_more_lin <= aWin->y_size - (r.bottom - r.top) / aWin->row_height) { aWin->last_more_lin = aWin->y_size; mac_display_nhwindow(win, TRUE); } } /* * A "default" text window - uses TETextBox * We just add the text, without attributes for now */ len = GetHandleSize(aWin->windowText); while (aWin->windowTextLen + slen + 1 > len) { len = (len > 2048) ? (len + 2048) : (len * 2); SetHandleSize(aWin->windowText, len); if (MemError()) { error("putstr: SetHandleSize"); aWin->windowTextLen = 0L; aWin->save_lin = 0; aWin->y_curs = 0; aWin->y_size = 0; } } len = aWin->windowTextLen; dst = *(aWin->windowText) + len; sline = src = (char *) str; maxWidth = newWidth = 0; for (ch = *src; ch; ch = *src) { if (ch == CHAR_LF) ch = CHAR_CR; *dst++ = ch; if (ch == CHAR_CR) { aWin->y_curs++; aWin->y_size++; aWin->x_curs = 0; newWidth = TextWidth(sline, 0, src - sline); if (newWidth > maxWidth) { maxWidth = newWidth; } sline = src + 1; /* keep track of where new line begins */ } else aWin->x_curs++; src++; } newWidth = TextWidth(sline, 0, src - sline); if (newWidth > maxWidth) { maxWidth = newWidth; } aWin->windowTextLen += slen; if (ch != CHAR_CR) { (*(aWin->windowText))[len + slen] = CHAR_CR; aWin->windowTextLen++; aWin->y_curs++; aWin->y_size++; aWin->x_curs = 0; } if (win == WIN_MESSAGE) { short min = aWin->y_size - (r.bottom - r.top) / aWin->row_height; if (aWin->scrollPos < min) { aWin->scrollPos = min; SetControlMaximum(aWin->scrollBar, aWin->y_size); SetControlValue(aWin->scrollBar, min); } InvalWindowRect(aWin->its_window, &r); } else /* Message has a fixed width, other windows base on content */ if (maxWidth > aWin->x_size) aWin->x_size = maxWidth; in_putstr--; } void mac_curs(winid win, int x, int y) { NhWindow *aWin = &theWindows[win]; if (aWin->its_window == _mt_window) { tty_curs(win, x, y); return; } SetPortWindowPort(aWin->its_window); MoveTo(x * aWin->char_width, (y * aWin->row_height) + aWin->ascent_height); aWin->x_curs = x; aWin->y_curs = y; } int mac_nh_poskey(int *a, int *b, int *c) { int ch = mac_nhgetch(); *a = clicked_pos.h; *b = clicked_pos.v; *c = clicked_mod; return ch; } void mac_start_menu(winid win, unsigned long mbehavior) { HideWindow(theWindows[win].its_window); mac_clear_nhwindow(win); } void mac_add_menu(winid win, int glyph, const anything *any, CHAR_P menuChar, CHAR_P groupAcc, int attr, const char *inStr, unsigned int itemflags) { #if defined(__SC__) || defined(__MRC__) #pragma unused(glyph) #endif NhWindow *aWin = &theWindows[win]; const char *str; char locStr[4 + BUFSZ]; MacMHMenuItem *item; int preselected = ((itemflags & MENU_ITEMFLAGS_SELECTED) != 0); if (!inStr) return; if (any->a_void != 0) { #define kMenuSizeBump 26 if (!aWin->miSize) { aWin->menuInfo = (MacMHMenuItem **) NewHandle( sizeof(MacMHMenuItem) * kMenuSizeBump); if (!aWin->menuInfo) { error("Can't alloc menu handle"); return; } aWin->menuSelected = (short **) NewHandle(sizeof(short) * kMenuSizeBump); if (!aWin->menuSelected) { error("Can't alloc menu select handle"); return; } aWin->miSize = kMenuSizeBump; } if (aWin->miLen >= aWin->miSize) { SetHandleSize((Handle) aWin->menuInfo, sizeof(MacMHMenuItem) * (aWin->miLen + kMenuSizeBump)); if (MemError()) { error("Can't resize menu handle"); return; } SetHandleSize((Handle) aWin->menuSelected, sizeof(short) * (aWin->miLen + kMenuSizeBump)); if (MemError()) { error("Can't resize menu select handle"); return; } aWin->miSize += kMenuSizeBump; } if (menuChar == 0) { if (('a' <= aWin->menuChar && aWin->menuChar <= 'z') || ('A' <= aWin->menuChar && aWin->menuChar <= 'Z')) { menuChar = aWin->menuChar++; if (menuChar == 'z') aWin->menuChar = 'A'; } } Sprintf(locStr, "%c - %s", (menuChar ? menuChar : ' '), inStr); str = locStr; HLock((char **) aWin->menuInfo); HLock((char **) aWin->menuSelected); (*aWin->menuSelected)[aWin->miLen] = preselected; item = &(*aWin->menuInfo)[aWin->miLen]; aWin->miLen++; item->id = *any; item->accelerator = menuChar; item->groupAcc = groupAcc; item->line = aWin->y_size; HUnlock((char **) aWin->menuInfo); HUnlock((char **) aWin->menuSelected); } else str = inStr; putstr(win, attr, str); } /* * End a menu in this window, window must a type NHW_MENU. * str is a list of cancel characters (values that may be input) * morestr is a prompt to display, rather than the default. * str and morestr might be ignored by some ports. */ void mac_end_menu(winid win, const char *morestr) { Str255 buf; NhWindow *aWin = &theWindows[win]; buf[0] = 0; if (morestr) C2P(morestr, buf); SetWTitle(aWin->its_window, buf); } int mac_select_menu(winid win, int how, menu_item **selected_list) { int c; NhWindow *aWin = &theWindows[win]; WindowPtr theWin = aWin->its_window; inSelect = win; mac_display_nhwindow(win, FALSE); aWin->how = (short) how; for (;;) { c = map_menu_cmd(mac_nhgetch()); if (c == CHAR_ESC) { /* deselect everything */ aWin->miSelLen = 0; break; } else if (ClosingWindowChar(c)) { break; } else { nhbell(); } } HideWindow(theWin); if (aWin->miSelLen) { menu_item *mp; MacMHMenuItem *mi; *selected_list = mp = (menu_item *) alloc(aWin->miSelLen * sizeof(menu_item)); HLock((char **) aWin->menuInfo); HLock((char **) aWin->menuSelected); for (c = 0; c < aWin->miSelLen; c++) { mi = &(*aWin->menuInfo)[(*aWin->menuSelected)[c]]; mp->item = mi->id; mp->count = -1L; mp++; } HUnlock((char **) aWin->menuInfo); HUnlock((char **) aWin->menuSelected); } else *selected_list = 0; inSelect = WIN_ERR; return aWin->miSelLen; } #include "dlb.h" static void mac_display_file(name, complain) const char *name; /* not ANSI prototype because of boolean parameter */ boolean complain; { Ptr buf; int win; dlb *fp = dlb_fopen(name, "r"); if (fp) { long l = dlb_fseek(fp, 0, SEEK_END); (void) dlb_fseek(fp, 0, 0L); buf = NewPtr(l + 1); if (buf) { l = dlb_fread(buf, 1, l, fp); if (l > 0) { buf[l] = '\0'; win = create_nhwindow(NHW_TEXT); if (WIN_ERR == win) { if (complain) error("Cannot make window."); } else { putstr(win, 0, buf); display_nhwindow(win, FALSE); } } DisposePtr(buf); } dlb_fclose(fp); } else if (complain) error("Cannot open %s.", name); } void port_help() { display_file(PORT_HELP, TRUE); } static void mac_unimplemented(void) { } static void mac_suspend_nhwindows(const char *foo) { #if defined(__SC__) || defined(__MRC__) #pragma unused(foo) #endif /* Can't really do that :-) */ } int try_key_queue(char *bufp) { if (keyQueueCount) { char ch; for (ch = GetFromKeyQueue();; ch = GetFromKeyQueue()) { if (ch == CHAR_LF || ch == CHAR_CR) ch = 0; *bufp++ = ch; if (ch == 0) break; } return 1; } return 0; } /********************************************************************** * Base window */ static void BaseClick(NhWindow *wind, Point pt, UInt32 modifiers) { pt.h = pt.h / wind->char_width + 1; pt.v = pt.v / wind->row_height; clicked_mod = (modifiers & shiftKey) ? CLICK_2 : CLICK_1; if (strchr(topl_resp, *click_to_cmd(pt.h, pt.v, clicked_mod))) nhbell(); else { #if 1 //!TARGET_API_MAC_CARBON if (cursor_locked) while (WaitMouseUp()) /*SystemTask()*/; #endif gClickedToMove = TRUE; clicked_pos = pt; } return; } static void BaseCursor(NhWindow *wind, Point pt) { char *dir_bas, *dir; CursHandle ch; if (cursor_locked) dir = (char *) 0; else { dir_bas = (char *) Cmd.dirchars; dir = strchr(dir_bas, *click_to_cmd(pt.h / wind->char_width + 1, pt.v / wind->row_height, CLICK_1)); } ch = GetCursor(dir ? dir - dir_bas + 513 : 512); if (ch) { HLock((Handle) ch); SetCursor(*ch); HUnlock((Handle) ch); } else { SetCursor(&qdarrow); } return; } #if 0 // TARGET_API_MAC_CARBON static pascal OSStatus BaseEvent(EventHandlerCallRef nexthandler, EventRef event, void *userdata) { NhWindow *wind = (NhWindow *) userdata; switch (GetEventClass(event)) { case kEventClassKeyboard: { char ch; UInt32 modifiers; GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ch); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); if (modifiers & cmdKey) return (eventNotHandledErr); AddToKeyQueue(topl_resp_key(ch), TRUE); return (noErr); } case kEventClassMouse: { CGrafPtr saveport; GDHandle savedev; Point pt; switch (GetEventKind(event)) { case kEventMouseMoved: GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pt); GetGWorld(&saveport, &savedev); SetPortWindowPort(wind->its_window); GlobalToLocal(&pt); SetGWorld(saveport, savedev); BaseCursor(wind, pt); return (eventNotHandledErr); } break; } case kEventClassWindow: switch (GetEventKind(event)) { case kEventWindowDrawContent: CallNextEventHandler(nexthandler, event); image_tty(NULL, wind->its_window); return (noErr); case kEventWindowHandleContentClick: { CGrafPtr saveport; GDHandle savedev; Point pt; UInt32 modifiers; GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pt); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); GetGWorld(&saveport, &savedev); SetPortWindowPort(wind->its_window); GlobalToLocal(&pt); SetGWorld(saveport, savedev); BaseClick(wind, pt, modifiers); return (noErr); } case kEventWindowClose: /* TODO... */ break; } break; } return (eventNotHandledErr); } #else static void macClickTerm(EventRecord *theEvent, WindowPtr theWindow) { Point where = theEvent->where; GlobalToLocal(&where); BaseClick(GetNhWin(theWindow), where, theEvent->modifiers); return; } static void macCursorTerm(EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) { GrafPtr gp; Point where = theEvent->where; Rect r = { 0, 0, 1, 1 }; GetPort(&gp); SetPortWindowPort(theWindow); GlobalToLocal(&where); BaseCursor(GetNhWin(theWindow), where); OffsetRect(&r, theEvent->where.h, theEvent->where.v); RectRgn(mouseRgn, &r); SetPort(gp); return; } #endif /* !TARGET_API_MAC_CARBON */ /********************************************************************** * Status subwindow */ /********************************************************************** * Map subwindow */ /********************************************************************** * Message window */ static void MsgClick(NhWindow *wind, Point pt) { int r_idx = 0; while (topl_resp[r_idx]) { Rect frame; topl_resp_rect(r_idx, &frame); InsetRect(&frame, 1, 1); if (PtInRect(pt, &frame)) { Boolean in_btn = true; InvertRect(&frame); while (WaitMouseUp()) { #if !TARGET_API_MAC_CARBON SystemTask(); #endif GetMouse(&pt); if (PtInRect(pt, &frame) != in_btn) { in_btn = !in_btn; InvertRect(&frame); } } if (in_btn) { InvertRect(&frame); AddToKeyQueue(topl_resp[r_idx], 1); } return; } ++r_idx; } return; } static void MsgUpdate(NhWindow *wind) { RgnHandle org_clip = NewRgn(), clip = NewRgn(); Rect r; int l; GetClip(org_clip); GetWindowBounds(wind->its_window, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); DrawControls(wind->its_window); DrawGrowIcon(wind->its_window); for (l = 0; topl_resp[l]; l++) { StringPtr name; unsigned char tmp[2]; FontInfo font; Rect frame; topl_resp_rect(l, &frame); switch (topl_resp[l]) { case 'y': name = "\pyes"; break; case 'n': name = "\pno"; break; case 'N': name = "\pNone"; break; case 'a': name = "\pall"; break; case 'q': name = "\pquit"; break; case CHAR_ANY: name = "\pany key"; break; default: tmp[0] = 1; tmp[1] = topl_resp[l]; name = tmp; break; } TextFont(kFontIDGeneva); TextSize(9); GetFontInfo(&font); MoveTo((frame.left + frame.right - StringWidth(name)) / 2, (frame.top + frame.bottom + font.ascent - font.descent - font.leading - 1) / 2); DrawString(name); PenNormal(); if (l == topl_def_idx) PenSize(2, 2); FrameRoundRect(&frame, 4, 4); } r.right -= SBARWIDTH; r.bottom -= SBARHEIGHT; /* Clip to the portrect - scrollbar/growicon *before* adjusting the rect to be larger than the size of the window (!) */ RectRgn(clip, &r); SectRgn(clip, org_clip, clip); if (r.right < MIN_RIGHT) r.right = MIN_RIGHT; r.top -= wind->scrollPos * wind->row_height; #if 0 /* If you enable this band of code (and disable the next band), you will get fewer flickers but a slower performance while drawing the dot line. */ { RgnHandle dotl_rgn = NewRgn(); Rect dotl; dotl.left = r.left; dotl.right = r.right; dotl.bottom = r.top + aWin->save_lin * aWin->row_height; dotl.top = dotl.bottom - 1; FillRect(&dotl, &qd.gray); RectRgn(dotl_rgn, &dotl); DiffRgn(clip, dotl_rgn, clip); DisposeRgn(dotl_rgn); SetClip(clip); } #endif if (in_topl_mode()) { RgnHandle topl_rgn = NewRgn(); Rect topl_r = r; topl_r.top += (wind->y_size - 1) * wind->row_height; l = (*top_line)->destRect.right - (*top_line)->destRect.left; (*top_line)->viewRect = topl_r; (*top_line)->destRect = topl_r; if (l != topl_r.right - topl_r.left) TECalText(top_line); TEUpdate(&topl_r, top_line); RectRgn(topl_rgn, &topl_r); DiffRgn(clip, topl_rgn, clip); DisposeRgn(topl_rgn); SetClip(clip); } DisposeRgn(clip); TextFont(wind->font_number); TextSize(wind->font_size); HLock(wind->windowText); TETextBox(*wind->windowText, wind->windowTextLen, &r, teJustLeft); HUnlock(wind->windowText); #if !TARGET_API_MAC_CARBON r.bottom = r.top + aWin->save_lin * aWin->row_height; r.top = r.bottom - 1; FillRect(&r, (void *) &qd.gray); #endif SetClip(org_clip); DisposeRgn(org_clip); return; } #if 0 // TARGET_API_MAC_CARBON static pascal OSStatus MsgEvent(EventHandlerCallRef nexthandler, EventRef event, void *userdata) { NhWindow *wind = (NhWindow *) userdata; switch (GetEventClass(event)) { case kEventClassControl: { ControlRef control; ControlID id; switch (GetEventKind(event)) { case kEventControlHit: GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control); GetControlID(control, &id); /* TODO... */ return (noErr); } break; } case kEventClassKeyboard: { char ch; UInt32 modifiers; GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ch); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); if (modifiers & cmdKey) return (eventNotHandledErr); AddToKeyQueue(topl_resp_key(ch), TRUE); return (noErr); } case kEventClassWindow: switch (GetEventKind(event)) { case kEventWindowDrawContent: CallNextEventHandler(nexthandler, event); MsgUpdate(wind); return (noErr); case kEventWindowHandleContentClick: { CGrafPtr saveport; GDHandle savedev; Point pt; GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pt); GetGWorld(&saveport, &savedev); SetPortWindowPort(wind->its_window); GlobalToLocal(&pt); SetGWorld(saveport, savedev); MsgClick(wind, pt); return (noErr); } case kEventWindowClose: /* TODO... */ break; } break; } return (eventNotHandledErr); } #else static void macClickMessage(EventRecord *theEvent, WindowPtr theWindow) { Point mouse = theEvent->where; GlobalToLocal(&mouse); MsgClick(GetNhWin(theWindow), mouse); macClickText(theEvent, theWindow); } static short macUpdateMessage(EventRecord *theEvent, WindowPtr theWindow) { if (!theEvent) return 0; MsgUpdate(GetNhWin(theWindow)); return 0; } #endif /* !TARGET_API_MAC_CARBON */ /********************************************************************** * Menu windows */ static void MenwKey(NhWindow *wind, char ch) { MacMHMenuItem *mi; int i; ch = filter_scroll_key(ch, wind); if (!ch) return; if (ClosingWindowChar(ch)) { AddToKeyQueue(CHAR_CR, 1); return; } if (!wind || !wind->menuInfo) return; HLock((char **) wind->menuInfo); for (i = 0, mi = *wind->menuInfo; i < wind->miLen; i++, mi++) { if (mi->accelerator == ch) { ToggleMenuListItemSelected(wind, i); if (mi->line >= wind->scrollPos && mi->line <= wind->y_size) { SetPortWindowPort(wind->its_window); ToggleMenuSelect(wind, mi->line - wind->scrollPos); } /* Dismiss window if only picking one item */ if (wind->how != PICK_ANY) AddToKeyQueue(CHAR_CR, 1); break; } } HUnlock((char **) wind->menuInfo); /* add key if didn't find it in menu and not filtered */ return; } static void MenwClick(NhWindow *wind, Point pt) { Rect wrect; GetWindowBounds(wind->its_window, kWindowContentRgn, &wrect); OffsetRect(&wrect, -wrect.left, -wrect.top); if (inSelect != WIN_ERR && wind->how != PICK_NONE) { short currentRow = -1, previousRow = -1; short previousItem = -1, item = -1; Boolean majorSelectState, firstRow = TRUE; do { #if !TARGET_API_MAC_CARBON SystemTask(); #endif GetMouse(&pt); currentRow = pt.v / wind->row_height; if (pt.h < wrect.left || pt.h > wrect.right || pt.v < 0 || pt.v > wrect.bottom || currentRow >= wind->y_size) { continue; /* not in window range */ } item = ListCoordinateToItem(wind, currentRow); if (item != previousItem) { /* Implement typical Mac multiple-selection behavior * (ie, not the UI implemented by the Finder) */ Boolean itemIsSelected = (ListItemSelected(wind, item) >= 0); if (firstRow) { /* this is first valid row, so major state is opposite of * what this row is */ majorSelectState = !itemIsSelected; firstRow = FALSE; } if (wind->how == PICK_ONE && previousItem != -1) { /* if previous row was selected and we're only selecting * one object, * deselect previous row! */ ToggleMenuListItemSelected(wind, previousItem); ToggleMenuSelect(wind, previousRow); previousItem = -1; } if (item == -1) continue; /* header line */ if (majorSelectState != itemIsSelected) { ToggleMenuListItemSelected(wind, item); ToggleMenuSelect(wind, currentRow); } previousRow = currentRow; previousItem = item; } } while (StillDown()); /* Dismiss window if only picking one item */ if (wind->how == PICK_ONE) AddToKeyQueue(CHAR_CR, 1); } return; } static void MenwUpdate(NhWindow *wind) { int i, line; MacMHMenuItem *mi; TextUpdate(wind); HLock((Handle) wind->menuInfo); HLock((Handle) wind->menuSelected); for (i = 0; i < wind->miSelLen; i++) { mi = &(*wind->menuInfo)[(*wind->menuSelected)[i]]; line = mi->line; if (line > wind->scrollPos && line <= wind->y_size) ToggleMenuSelect(wind, line - wind->scrollPos); } HUnlock((Handle) wind->menuInfo); HUnlock((Handle) wind->menuSelected); return; } #if 0 // TARGET_API_MAC_CARBON static pascal OSStatus MenwEvent(EventHandlerCallRef nexthandler, EventRef event, void *userdata) { NhWindow *wind = (NhWindow *) userdata; switch (GetEventClass(event)) { case kEventClassControl: { ControlRef control; ControlID id; switch (GetEventKind(event)) { case kEventControlHit: GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control); GetControlID(control, &id); /* TODO... */ return (noErr); } break; } case kEventClassKeyboard: { char ch; UInt32 modifiers; GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ch); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); if (modifiers & cmdKey) return (eventNotHandledErr); MenwKey(wind, ch); return (noErr); } case kEventClassWindow: switch (GetEventKind(event)) { case kEventWindowDrawContent: CallNextEventHandler(nexthandler, event); MenwUpdate(wind); return (noErr); case kEventWindowHandleContentClick: { CGrafPtr saveport; GDHandle savedev; Point pt; GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pt); GetGWorld(&saveport, &savedev); SetPortWindowPort(wind->its_window); GlobalToLocal(&pt); SetGWorld(saveport, savedev); MenwClick(wind, pt); return (noErr); } case kEventWindowClose: /* TODO... */ break; } break; } return (eventNotHandledErr); } #else static void macKeyMenu(EventRecord *theEvent, WindowPtr theWindow) { MenwKey(GetNhWin(theWindow), theEvent->message & 0xff); return; } static void macClickMenu(EventRecord *theEvent, WindowRef theWindow) { Point p; NhWindow *aWin = GetNhWin(theWindow); if (aWin->scrollBar && IsControlVisible(aWin->scrollBar)) { short code; ControlHandle theBar; p = theEvent->where; GlobalToLocal(&p); code = FindControl(p, theWindow, &theBar); if (code) { DoScrollBar(p, code, theBar, aWin); return; } } MenwClick(aWin, theEvent->where); } static short macUpdateMenu(EventRecord *theEvent, WindowPtr theWindow) { MenwUpdate(GetNhWin(theWindow)); return 0; } #endif /* !TARGET_API_MAC_CARBON */ /********************************************************************** * Text windows */ static void TextKey(NhWindow *wind, char ch) { ch = filter_scroll_key(ch, wind); if (!ch) return; if (inSelect == WIN_ERR && ClosingWindowChar(ch)) { HideWindow(wind->its_window); mac_destroy_nhwindow(wind - theWindows); } else AddToKeyQueue(topl_resp_key(ch), TRUE); return; } static void TextUpdate(NhWindow *wind) { Rect r, r2; RgnHandle h; Boolean vis; GetWindowBounds(wind->its_window, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); r2 = r; r2.left = r2.right - SBARWIDTH; r2.right += 1; r2.top -= 1; vis = (r2.bottom > r2.top + 50); draw_growicon_vert_only(wind->its_window); DrawControls(wind->its_window); h = (RgnHandle) 0; if (vis && (h = NewRgn())) { RgnHandle tmp = NewRgn(); if (!tmp) { DisposeRgn(h); h = (RgnHandle) 0; } else { GetClip(h); RectRgn(tmp, &r2); DiffRgn(h, tmp, tmp); SetClip(tmp); DisposeRgn(tmp); } } if (r.right < MIN_RIGHT) r.right = MIN_RIGHT; r.top -= wind->scrollPos * wind->row_height; r.right -= SBARWIDTH; HLock(wind->windowText); TETextBox(*wind->windowText, wind->windowTextLen, &r, teJustLeft); HUnlock(wind->windowText); if (h) { SetClip(h); DisposeRgn(h); } return; } #if 0 // TARGET_API_MAC_CARBON static pascal OSStatus TextEvent(EventHandlerCallRef nexthandler, EventRef event, void *userdata) { NhWindow *wind = (NhWindow *) userdata; switch (GetEventClass(event)) { case kEventClassControl: { ControlRef control; ControlID id; switch (GetEventKind(event)) { case kEventControlHit: GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control); GetControlID(control, &id); /* TODO... */ return (noErr); } break; } case kEventClassKeyboard: { char ch; UInt32 modifiers; GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ch); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); if (modifiers & cmdKey) return (eventNotHandledErr); TextKey(wind, ch); return (noErr); } case kEventClassWindow: switch (GetEventKind(event)) { case kEventWindowDrawContent: CallNextEventHandler(nexthandler, event); TextUpdate(wind); return (noErr); case kEventWindowClose: /* TODO... */ break; } break; } return (eventNotHandledErr); } #else static void macKeyText(EventRecord *theEvent, WindowPtr theWindow) { TextKey(GetNhWin(theWindow), theEvent->message & 0xff); return; } static void macClickText(EventRecord *theEvent, WindowPtr theWindow) { NhWindow *aWin = GetNhWin(theWindow); if (aWin->scrollBar && IsControlVisible(aWin->scrollBar)) { short code; Point p = theEvent->where; ControlHandle theBar; GlobalToLocal(&p); code = FindControl(p, theWindow, &theBar); if (code) { DoScrollBar(p, code, theBar, aWin); } } } #endif /* !TARGET_API_MAC_CARBON */ /********************************************************************** * Global events */ #if 0 // TARGET_API_MAC_CARBON static pascal OSStatus GlobalEvent(EventHandlerCallRef nexthandler, EventRef event, void *userdata) { switch (GetEventClass(event)) { case kEventClassCommand: return (eventNotHandledErr); } return (eventNotHandledErr); } #else static short macDoNull(EventRecord *theEvent, WindowPtr theWindow) { return 0; } /* * Note; theWindow may very well be null here, since keyDown may call * it when theres no window !!! */ /* NOT_IN_CARBON */ static void GeneralKey(EventRecord *theEvent, WindowPtr theWindow) { #if defined(__SC__) || defined(__MRC__) #pragma unused(theWindow) #endif #if 0 trans_num_keys (theEvent); #endif AddToKeyQueue(topl_resp_key(theEvent->message & 0xff), TRUE); } static void HandleKey(EventRecord *theEvent) { WindowPtr theWindow = FrontWindow(); if (theEvent->modifiers & cmdKey) { if (theEvent->message & 0xff == '.') { /* Flush key queue */ keyQueueCount = keyQueueWrite = keyQueueRead = 0; theEvent->message = '\033'; goto dispatchKey; } else { UndimMenuBar(); DoMenuEvt(MenuKey(theEvent->message & 0xff)); } } else { dispatchKey: if (theWindow) { int kind = GetWindowKind(theWindow) - WIN_BASE_KIND; winKeyFuncs[kind](theEvent, theWindow); } else { GeneralKey(theEvent, (WindowPtr) 0); } } } #endif /* !TARGET_API_MAC_CARBON */ static void HandleClick(EventRecord *theEvent) { int code; unsigned long l; WindowPtr theWindow; NhWindow *aWin; Rect r; Boolean not_inSelect; InsetRect(GetRegionBounds(GetGrayRgn(), &r), 4, 4); code = FindWindow(theEvent->where, &theWindow); aWin = GetNhWin(theWindow); not_inSelect = (inSelect == WIN_ERR || aWin - theWindows == inSelect); switch (code) { case inContent: #if 1 //!TARGET_API_MAC_CARBON if (not_inSelect) { int kind = GetWindowKind(theWindow) - WIN_BASE_KIND; winCursorFuncs[kind](theEvent, theWindow, gMouseRgn); SelectWindow(theWindow); SetPortWindowPort(theWindow); winClickFuncs[kind](theEvent, theWindow); } else { nhbell(); } #endif break; case inDrag: if (not_inSelect) { SetCursor(&qdarrow); DragWindow(theWindow, theEvent->where, &r); SaveWindowPos(theWindow); } else { nhbell(); } break; case inGrow: if (not_inSelect) { SetCursor(&qdarrow); SetRect(&r, 80, 2 * aWin->row_height + 1, r.right, r.bottom); if (aWin == theWindows + WIN_MESSAGE) r.top += SBARHEIGHT; l = GrowWindow(theWindow, theEvent->where, &r); SizeWindow(theWindow, l & 0xffff, l >> 16, FALSE); SaveWindowSize(theWindow); SetPortWindowPort(theWindow); GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); InvalWindowRect(theWindow, &r); if (aWin->scrollBar) { DrawScrollbar(aWin); } } else { nhbell(); } break; case inGoAway: WindowGoAway(theEvent, theWindow); break; case inMenuBar: DoMenuEvt(MenuSelect(theEvent->where)); break; #if !TARGET_API_MAC_CARBON case inSysWindow: SystemClick(theEvent, theWindow); #endif default: break; } } #if 1 //!TARGET_API_MAC_CARBON static short GeneralUpdate(EventRecord *theEvent, WindowPtr theWindow) { if (!theEvent) return 0; TextUpdate(GetNhWin(theWindow)); return 0; } #endif static void HandleUpdate(EventRecord *theEvent) { WindowPtr theWindow = (WindowPtr) theEvent->message; NhWindow *aWin = GetNhWin(theWindow); Rect r; #if 1 //!TARGET_API_MAC_CARBON EventRecord fake; #endif char existing_update_region = FALSE; Rect rect; if (theWindow == _mt_window) { existing_update_region = (get_invalid_region(theWindow, &rect) == noErr); } BeginUpdate(theWindow); SetPortWindowPort(theWindow); GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); EraseRect(&r); #if 0 // TARGET_API_MAC_CARBON switch (GetWindowKind(theWindow) - WIN_BASE_KIND) { case NHW_BASE: case NHW_MAP: case NHW_STATUS: image_tty(NULL, theWindow); break; case NHW_MESSAGE: MsgUpdate(GetNhWin(theWindow)); break; case NHW_MENU: MenwUpdate(GetNhWin(theWindow)); break; case NHW_TEXT: TextUpdate(GetNhWin(theWindow)); break; } #else winUpdateFuncs[GetWindowKind(theWindow) - WIN_BASE_KIND](&fake, theWindow); #endif if (theWindow == _mt_window && existing_update_region) { set_invalid_region(theWindow, &rect); } aWin->drawn = TRUE; EndUpdate(theWindow); } #if 1 //!TARGET_API_MAC_CARBON static void GeneralCursor(EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) { #if defined(__SC__) || defined(__MRC__) #pragma unused(theWindow) #endif Rect r = { -1, -1, 2, 2 }; SetCursor(&qdarrow); OffsetRect(&r, theEvent->where.h, theEvent->where.v); RectRgn(mouseRgn, &r); } static void DoOsEvt(EventRecord *theEvent) { WindowRef win; short code; if ((theEvent->message & 0xff000000) == 0xfa000000) { /* Mouse Moved */ code = FindWindow(theEvent->where, &win); if (code != inContent) { Rect r = { -1, -1, 2, 2 }; SetCursor(&qdarrow); OffsetRect(&r, theEvent->where.h, theEvent->where.v); RectRgn(gMouseRgn, &r); } else { #if 1 //!TARGET_API_MAC_CARBON int kind = GetWindowKind(win) - WIN_BASE_KIND; if (kind >= 0 && kind <= NHW_TEXT) { winCursorFuncs[kind](theEvent, win, gMouseRgn); } #endif } } } #endif /* !TARGET_API_MAC_CARBON */ void HandleEvent(EventRecord *theEvent) { switch (theEvent->what) { #if 1 //!TARGET_API_MAC_CARBON case autoKey: case keyDown: HandleKey(theEvent); break; #endif case updateEvt: HandleUpdate(theEvent); break; case mouseDown: HandleClick(theEvent); break; #if !TARGET_API_MAC_CARBON case diskEvt: if ((theEvent->message & 0xffff0000) != 0) { Point p = { 150, 150 }; (void) DIBadMount(p, theEvent->message); } break; #endif #if !TARGET_API_MAC_CARBON case osEvt: DoOsEvt(theEvent); break; #endif case kHighLevelEvent: AEProcessAppleEvent(theEvent); default: break; } } /********************************************************************** * Interface definition, for windows.c */ struct window_procs mac_procs = { "mac", WC_COLOR | WC_HILITE_PET | WC_FONT_MAP | WC_FONT_MENU | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_TEXT | WC_FONTSIZ_MAP | WC_FONTSIZ_MENU | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_TEXT, 0L, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ mac_init_nhwindows, mac_unimplemented, /* see macmenu.c:mac_askname() for player selection */ mac_askname, mac_get_nh_event, mac_exit_nhwindows, mac_suspend_nhwindows, mac_unimplemented, mac_create_nhwindow, mac_clear_nhwindow, mac_display_nhwindow, mac_destroy_nhwindow, mac_curs, mac_putstr, genl_putmixed, mac_display_file, mac_start_menu, mac_add_menu, mac_end_menu, mac_select_menu, genl_message_menu, mac_unimplemented, mac_get_nh_event, mac_get_nh_event, #ifdef CLIPPING mac_cliparound, #endif #ifdef POSITIONBAR donull, #endif tty_print_glyph, tty_raw_print, tty_raw_print_bold, mac_nhgetch, mac_nh_poskey, tty_nhbell, mac_doprev_message, mac_yn_function, mac_getlin, mac_get_ext_cmd, mac_number_pad, mac_delay_output, #ifdef CHANGE_COLOR tty_change_color, tty_change_background, set_tty_font_name, tty_get_color_string, #endif genl_outrip, genl_preference_update, genl_can_suspend_no, }; /*macwin.c*/