Files
nethack/sys/mac/macwin.c
cohrs 559be58c21 conflicting delayed killers
Introduce a new set of functions to manage delayed killers in the trunk, used
in addressing the various reports of delayed killer confusion.  Since existing
delayed killers are related to player properties, the delayed killers are
keyed by uprop indexes.  I did this to avoid adding yet another set of
similar identifiers.
- the new delayed_killer() is used for stoning, sliming, sickness, and
delayed self-genocide while polymorphed.  Some other timed events don't
use it (and didn't use the old delayed_killer variable) because they
use a fixed message when the timeout occurs.
- A new data structure, struct kinfo, is used to track both delayed and
immediate killers.  This encapsulates all the info involved with
identifying a killer.  The structure contains a buffer, which subsumes the
old killer_buf and several other buffers that didn't/couldn't use killer_buf.
- the killer list is saved and restored as part of the game state.
- the special case of usick_cause was removed and a delayed killer list
entry is now used in its place
- common code dealing with (un)sliming is moved to a new make_slimed function
- attempted to update all make dependencies for new end.c -> lev.h
dependency, sorry if I messed any up
2003-09-29 19:24:20 +00:00

2651 lines
62 KiB
C

/* SCCS Id: @(#)macwin.c 3.4 1996/01/15 */
/* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#include "func_tab.h"
#include "macwin.h"
#include "mactty.h"
#include "wintty.h"
#if !TARGET_API_MAC_CARBON
#include <LowMem.h>
#include <AppleEvents.h>
#include <Gestalt.h>
#include <TextUtils.h>
#include <DiskInit.h>
#include <ControlDefinitions.h>
#endif
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 FDECL(filter_scroll_key,(const int, NhWindow *));
static void FDECL(GeneralKey, (EventRecord *, WindowPtr));
static void FDECL(macKeyMenu, (EventRecord *, WindowPtr));
static void FDECL(macKeyText, (EventRecord *, WindowPtr));
static void FDECL(macClickMessage, (EventRecord *, WindowPtr));
static void FDECL(macClickTerm, (EventRecord *, WindowPtr));
static void FDECL(macClickMenu, (EventRecord *, WindowPtr));
static void FDECL(macClickText, (EventRecord *, WindowPtr));
static short FDECL(macDoNull, (EventRecord *, WindowPtr));
static short FDECL(macUpdateMessage, (EventRecord *, WindowPtr));
static short FDECL(macUpdateMenu, (EventRecord *, WindowPtr));
static short FDECL(GeneralUpdate, (EventRecord *, WindowPtr));
static void FDECL(macCursorTerm, (EventRecord *, WindowPtr, RgnHandle));
static void FDECL(GeneralCursor, (EventRecord *, WindowPtr, RgnHandle));
static void FDECL(DoScrollBar,(Point, short, ControlHandle, NhWindow *));
static pascal void FDECL(MoveScrollBar, (ControlHandle, short));
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
};
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("");
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
ConstrainWindowToScreen(_mt_window, kWindowStructureRgn,
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);
}
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);
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);
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_init_nhwindows (int *argcp, char **argv)
{
#if !TARGET_API_MAC_CARBON
Rect scr = (*GetGrayRgn())->rgnBBox;
small_screen = scr.bottom - scr.top <= (iflags.large_font ? 12*40 : 9*40);
#endif
Rect r;
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);
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);
ConstrainWindowToScreen(theWindows[NHW_MESSAGE].its_window, kWindowStructureRgn,
kWindowConstrainMoveRegardlessOfFit, NULL, NULL);
return;
}
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 ||
c == 'q';
}
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,
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);
if (aWin->scrollBar)
DrawScrollbar (aWin);
#endif
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.name[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) {
iflags.num_pad = pad;
}
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 (iflags.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
}
/*
* Note; theWindow may very well be null here, since keyDown may call
* it when theres no window !!!
*/
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);
}
/*
* 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 void
macKeyMenu (EventRecord *theEvent, WindowPtr theWindow) {
NhWindow *aWin = GetNhWin(theWindow);
MacMHMenuItem *mi;
int l, ch = theEvent->message & 0xff;
if (aWin && aWin->menuInfo) {
HLock ((char**)aWin->menuInfo);
for (l = 0, mi = *aWin->menuInfo; l < aWin->miLen; l++, mi++) {
if (mi->accelerator == ch) {
ToggleMenuListItemSelected (aWin, l);
if (mi->line >= aWin->scrollPos && mi->line <= aWin->y_size) {
SetPortWindowPort(theWindow);
ToggleMenuSelect (aWin, mi->line - aWin->scrollPos);
}
/* Dismiss window if only picking one item */
if (aWin->how != PICK_ANY)
AddToKeyQueue(CHAR_CR, 1);
break;
}
}
HUnlock ((char**)aWin->menuInfo);
/* add key if didn't find it in menu and not filtered */
if (l == aWin->miLen && filter_scroll_key (ch, aWin))
GeneralKey (theEvent, theWindow);
}
}
static void
macClickMenu (EventRecord *theEvent, WindowRef theWindow) {
Point p;
NhWindow *aWin = GetNhWin(theWindow);
Rect wrect;
GetWindowBounds(theWindow, kWindowContentRgn, &wrect);
OffsetRect(&wrect, -wrect.left, -wrect.top);
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;
}
}
if (inSelect != WIN_ERR && aWin->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 (&p);
currentRow = p.v / aWin->row_height;
if (p.h < wrect.left || p.h > wrect.right ||
p.v < 0 || p.v > wrect.bottom || currentRow >= aWin->y_size) {
continue; /* not in window range */
}
item = ListCoordinateToItem (aWin, currentRow);
if (item != previousItem) {
/* Implement typical Mac multiple-selection behavior
* (ie, not the UI implemented by the Finder)
*/
Boolean itemIsSelected = (ListItemSelected (aWin,item) >= 0);
if (firstRow) {
/* this is first valid row, so major state is opposite of what this row is */
majorSelectState = !itemIsSelected;
firstRow = FALSE;
}
if (aWin->how == PICK_ONE && previousItem != -1) {
/* if previous row was selected and we're only selecting one object,
* deselect previous row!
*/
ToggleMenuListItemSelected (aWin, previousItem);
ToggleMenuSelect (aWin, previousRow);
previousItem = -1;
}
if (item == -1)
continue; /* header line */
if (majorSelectState != itemIsSelected) {
ToggleMenuListItemSelected (aWin, item);
ToggleMenuSelect (aWin, currentRow);
}
previousRow = currentRow;
previousItem = item;
}
} while (StillDown ());
/* Dismiss window if only picking one item */
if (aWin->how == PICK_ONE)
AddToKeyQueue(CHAR_CR, 1);
}
}
static void
macKeyText (EventRecord *theEvent, WindowPtr theWindow) {
NhWindow *aWin = GetNhWin (theWindow);
char c = filter_scroll_key (theEvent->message & 0xff, aWin);
if (c) {
if (inSelect == WIN_ERR && ClosingWindowChar (c)) {
HideWindow (theWindow);
mac_destroy_nhwindow (aWin - theWindows);
} else {
GeneralKey (theEvent, theWindow);
}
}
}
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);
}
}
}
static void
macClickMessage (EventRecord *theEvent, WindowPtr theWindow) {
int r_idx = 0;
Point mouse = theEvent->where;
GlobalToLocal(&mouse);
while (topl_resp[r_idx]) {
Rect frame;
topl_resp_rect(r_idx, &frame);
InsetRect(&frame, 1, 1);
if (PtInRect(mouse, &frame)) {
Boolean in_btn = true;
InvertRect(&frame);
while (WaitMouseUp()) {
#if !TARGET_API_MAC_CARBON
SystemTask();
#endif
GetMouse(&mouse);
if (PtInRect(mouse, &frame) != in_btn) {
in_btn = !in_btn;
InvertRect(&frame);
}
}
if (in_btn) {
InvertRect(&frame);
AddToKeyQueue (topl_resp [r_idx], 1);
}
return;
}
++r_idx;
}
macClickText(theEvent, theWindow);
}
static void
macClickTerm (EventRecord *theEvent, WindowPtr theWindow) {
NhWindow *nhw = GetNhWin(theWindow);
Point where = theEvent->where;
GlobalToLocal(&where);
where.h = where.h / nhw->char_width + 1;
where.v = where.v / nhw->row_height;
clicked_mod = (theEvent->modifiers & shiftKey) ? CLICK_2 : CLICK_1;
if (strchr(topl_resp, *click_to_cmd(where.h, where.v, clicked_mod)))
nhbell();
else {
#if !TARGET_API_MAC_CARBON
if (cursor_locked)
while (WaitMouseUp())
SystemTask();
#endif
gClickedToMove = TRUE;
clicked_pos = where;
}
}
static pascal void
MoveScrollBar (ControlHandle theBar, short part) {
EventRecord fake;
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);
}
winUpdateFuncs [GetWindowKind(theWin) - WIN_BASE_KIND] (&fake, theWin);
if (rgn) {
EndUpdate(theWin);
DisposeRgn(rgn);
}
}
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);
}
}
}
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 short
macDoNull (EventRecord *theEvent, WindowPtr theWindow) {
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);
}
static short
macUpdateMessage (EventRecord *theEvent, WindowPtr theWindow)
{
RgnHandle org_clip = NewRgn(), clip = NewRgn();
Rect r;
NhWindow *aWin = GetNhWin(theWindow);
int l;
if (!theEvent)
return 0;
GetClip(org_clip);
GetWindowBounds(theWindow, kWindowContentRgn, &r);
OffsetRect(&r, -r.left, -r.top);
DrawControls(theWindow);
DrawGrowIcon(theWindow);
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 -= aWin->scrollPos * aWin->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 += (aWin->y_size - 1) * aWin->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 (aWin->font_number);
TextSize (aWin->font_size);
HLock (aWin->windowText);
TETextBox (*aWin->windowText, aWin->windowTextLen, &r, teJustLeft);
HUnlock (aWin->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 0;
}
static short
macUpdateMenu (EventRecord *theEvent, WindowPtr theWindow) {
NhWindow *aWin = GetNhWin (theWindow);
int i, line;
MacMHMenuItem *mi;
GeneralUpdate (theEvent, theWindow);
HLock ((char**)aWin->menuInfo);
HLock ((char**)aWin->menuSelected);
for (i = 0; i < aWin->miSelLen; i++) {
mi = &(*aWin->menuInfo) [(*aWin->menuSelected) [i]];
line = mi->line;
if (line > aWin->scrollPos && line <= aWin->y_size)
ToggleMenuSelect (aWin, line - aWin->scrollPos);
}
HUnlock ((char**)aWin->menuInfo);
HUnlock ((char**)aWin->menuSelected);
return 0;
}
static short
GeneralUpdate (EventRecord *theEvent, WindowPtr theWindow) {
Rect r, r2;
NhWindow *aWin = GetNhWin (theWindow);
RgnHandle h;
Boolean vis;
if (!theEvent)
return 0;
GetWindowBounds(theWindow, 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(theWindow);
DrawControls (theWindow);
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 -= aWin->scrollPos * aWin->row_height;
r.right -= SBARWIDTH;
HLock (aWin->windowText);
TETextBox (*aWin->windowText, aWin->windowTextLen, &r, teJustLeft);
HUnlock (aWin->windowText);
if (h) {
SetClip (h);
DisposeRgn (h);
}
return 0;
}
static void
macCursorTerm (EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) {
char *dir_bas, *dir;
CursHandle ch;
GrafPtr gp;
NhWindow *nhw = GetNhWin (theWindow);
Rect r = {0, 0, 1, 1};
GetPort (&gp);
SetPortWindowPort(theWindow);
if (cursor_locked)
dir = (char *)0;
else {
Point where = theEvent->where;
GlobalToLocal (&where);
dir_bas = iflags.num_pad ? (char *) ndir : (char *) sdir;
dir = strchr (dir_bas, *click_to_cmd (where.h / nhw->char_width + 1 ,
where.v / nhw->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);
}
OffsetRect (&r, theEvent->where.h, theEvent->where.v);
RectRgn (mouseRgn, &r);
SetPort (gp);
}
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
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);
}
}
}
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 */
}
}
}
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 (not_inSelect) {
int kind = GetWindowKind(theWindow) - WIN_BASE_KIND;
winCursorFuncs [kind] (theEvent, theWindow, gMouseRgn);
SelectWindow (theWindow);
SetPortWindowPort(theWindow);
winClickFuncs [kind] (theEvent, theWindow);
} else {
nhbell ();
}
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;
}
}
static void
HandleUpdate (EventRecord *theEvent) {
WindowPtr theWindow = (WindowPtr) theEvent->message;
NhWindow *aWin = GetNhWin (theWindow);
Rect r;
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);
winUpdateFuncs [GetWindowKind(theWindow) - WIN_BASE_KIND]
(theEvent, theWindow);
if (theWindow == _mt_window && existing_update_region) {
set_invalid_region (theWindow, &rect);
}
aWin->drawn = TRUE;
EndUpdate (theWindow);
}
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 {
int kind = GetWindowKind(win) - WIN_BASE_KIND;
if (kind >= 0 && kind <= NHW_TEXT) {
winCursorFuncs [kind] (theEvent, win, gMouseRgn);
}
}
}
}
void
HandleEvent (EventRecord *theEvent) {
switch (theEvent->what) {
case autoKey :
case keyDown :
HandleKey (theEvent);
break;
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
case osEvt :
DoOsEvt (theEvent);
break;
case kHighLevelEvent:
AEProcessAppleEvent(theEvent);
default :
break;
}
}
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;
(void) WaitNextEvent (everyEvent, &anEvent, -1, gMouseRgn);
HandleEvent(&anEvent);
}
int
mac_nhgetch(void) {
int ch;
long doDawdle;
EventRecord anEvent;
/* 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;
}
}
do {
(void) WaitNextEvent (everyEvent, &anEvent, doDawdle, gMouseRgn);
HandleEvent (&anEvent);
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) {
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, int preselected) {
#if defined(__SC__) || defined(__MRC__)
# pragma unused(glyph)
#endif
NhWindow *aWin = &theWindows [win];
const char *str;
char locStr[4+BUFSZ];
MacMHMenuItem *item;
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;
}
/* 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,
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,
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
/* other defs that really should go away (they're tty specific) */
0, // mac_start_screen,
0, // mac_end_screen,
genl_outrip,
genl_preference_update,
};
/*macwin.c*/