Files
nethack/sys/mac/macwin.c
nethack.allison 8fc01eb6b1 window port change - putmixed() (trunk only)
Add putmixed() to the window port. It allows map symbols to
be included in the string by encoding them in a unique fashion.
This was done because Unicode symbols, for instance, could be
longer than the size of a char.

The encoding of the map symbols in this patch is done by
prefixing a glyph value with \GXXXX, where XXXX is a
random value for the current game. The reason for the random
prefix is to minimize the possibility that a player can trigger
the escape sequence processing within text under their control
(dog names, etc.) the way they could if the sequence was fixed
in the source code. The random prefix remains the same throughout
the lifetime of a game because message window strings are
saved in the save file.

(There was actually a bug present because of the embedded
character even before the recent symbol changes, because if
someone was using a  different set of characters between games,
the saved messages would reflect the original characters, rather
than the current. That bug was introduced with the ability to
save messages to the savefile.)

A window port does not have to supply an XXX_putmixed() routine,
it can use genl_putmixed() which uses the old behavior of
embedding the sequence as a character within the string
and calling putstr(). genl_putmixed() takes care of the decoding
of the escape sequence.

This also #ifdef's out code in pager.c for converting a glyph
to a character, and uses mapglyph() to do that instead. Does
anyone see a problem with doing that through mapglyph instead
of repeating similar code within pager.c?
2006-10-17 23:06:31 +00:00

3298 lines
76 KiB
C

/* SCCS Id: @(#)macwin.c 3.5 2005/11/19 */
/* 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 <LowMem.h>
#include <AppleEvents.h>
#include <Gestalt.h>
#include <TextUtils.h>
#include <DiskInit.h>
#include <ControlDefinitions.h>
#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 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));
#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 FDECL(filter_scroll_key,(const int, NhWindow *));
#if 1//!TARGET_API_MAC_CARBON
static void FDECL(DoScrollBar,(Point, short, ControlHandle, NhWindow *));
#endif
static pascal void FDECL(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;
rmsg.right = rbase.right;
RetrievePosition(kMessageWindow, &rmsg.top, &rmsg.left);
if (RetrieveSize(kMessageWindow, rmsg.top, rmsg.left, &height, &width)) {
rmsg.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) {
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;
}
/**********************************************************************
* 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,
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
/* 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*/