1 /* SCCS Id: @(#)macwin.c 3.4 1996/01/15 */
2 /* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */
3 /* NetHack may be freely redistributed. See license for details. */
11 #if !TARGET_API_MAC_CARBON
13 #include <AppleEvents.h>
15 #include <TextUtils.h>
17 #include <ControlDefinitions.h>
20 NhWindow *theWindows = (NhWindow *) 0;
23 /* Borrowed from the Mac tty port */
24 extern WindowPtr _mt_window;
26 /* Some useful #defines for the scroll bar width and height */
31 * We put a TE on the message window for the "top line" queries.
32 * top_line is the TE that holds both the query and the user's
33 * response. The first topl_query_len characters in top_line are
34 * the query, the rests are the response. topl_resp is the valid
35 * response to a yn query, while topl_resp[topl_def_idx] is the
36 * default response to a yn query.
38 static TEHandle top_line = (TEHandle) nil;
39 static int topl_query_len;
40 static int topl_def_idx = -1;
41 static char topl_resp[10] = "";
46 * inSelect means we have a menu window up for selection or
47 * something similar. It makes the window with win number ==
48 * inSelect a movable modal (unfortunately without the border)
49 * and clicking the close box forces an RET into the key
50 * buffer. Don't forget to set inSelect to WIN_ERR when you're
53 static winid inSelect = WIN_ERR;
56 * The key queue ring buffer where Read is where to take from,
57 * Write is where next char goes and count is queue depth.
59 static unsigned char keyQueue [QUEUE_LEN];
60 static int keyQueueRead = 0,
64 static Boolean gClickedToMove = 0; /* For ObscureCursor */
66 static Point clicked_pos; /* For nh_poskey */
67 static int clicked_mod;
68 static Boolean cursor_locked = false;
70 static ControlActionUPP MoveScrollUPP; /* scrolling callback, init'ed in InitMac */
73 lock_mouse_cursor(Boolean new_cursor_locked) {
74 cursor_locked = new_cursor_locked;
79 * Add key to input queue, force means flush left and replace if full
82 AddToKeyQueue (unsigned char ch, Boolean force) {
83 if (keyQueueCount < QUEUE_LEN) {
84 keyQueue [keyQueueWrite++] = ch;
88 keyQueue [keyQueueWrite++] = ch;
90 if (keyQueueRead >= QUEUE_LEN)
92 keyQueueCount = QUEUE_LEN;
94 if (keyQueueWrite >= QUEUE_LEN)
103 GetFromKeyQueue (void) {
107 ret = keyQueue [keyQueueRead++];
109 if (keyQueueRead >= QUEUE_LEN)
121 static RgnHandle gMouseRgn = (RgnHandle) 0;
124 * _Gestalt madness - we rely heavily on the _Gestalt glue, since we
125 * don't check for the trap...
130 * The screen layouts on the small 512x342 screen need special cares.
132 Boolean small_screen = 0;
139 static int FDECL(filter_scroll_key,(const int, NhWindow *));
141 static void FDECL(GeneralKey, (EventRecord *, WindowPtr));
142 static void FDECL(macKeyMenu, (EventRecord *, WindowPtr));
143 static void FDECL(macKeyText, (EventRecord *, WindowPtr));
145 static void FDECL(macClickMessage, (EventRecord *, WindowPtr));
146 static void FDECL(macClickTerm, (EventRecord *, WindowPtr));
147 static void FDECL(macClickMenu, (EventRecord *, WindowPtr));
148 static void FDECL(macClickText, (EventRecord *, WindowPtr));
150 static short FDECL(macDoNull, (EventRecord *, WindowPtr));
151 static short FDECL(macUpdateMessage, (EventRecord *, WindowPtr));
152 static short FDECL(macUpdateMenu, (EventRecord *, WindowPtr));
153 static short FDECL(GeneralUpdate, (EventRecord *, WindowPtr));
155 static void FDECL(macCursorTerm, (EventRecord *, WindowPtr, RgnHandle));
156 static void FDECL(GeneralCursor, (EventRecord *, WindowPtr, RgnHandle));
158 static void FDECL(DoScrollBar,(Point, short, ControlHandle, NhWindow *));
159 static pascal void FDECL(MoveScrollBar, (ControlHandle, short));
161 typedef void (*CbFunc) (EventRecord *, WindowPtr);
162 typedef short (*CbUpFunc) (EventRecord *, WindowPtr);
163 typedef void (*CbCursFunc) (EventRecord *, WindowPtr, RgnHandle);
166 static const CbFunc winKeyFuncs [NUM_FUNCS] = {
167 GeneralKey, GeneralKey, GeneralKey, GeneralKey, macKeyMenu, macKeyText
170 static const CbFunc winClickFuncs [NUM_FUNCS] = {
171 (CbFunc)macDoNull, macClickMessage, macClickTerm, macClickTerm, macClickMenu,
175 static const CbUpFunc winUpdateFuncs [NUM_FUNCS] = {
176 macDoNull, macUpdateMessage, image_tty, image_tty,
177 macUpdateMenu, GeneralUpdate
180 static const CbCursFunc winCursorFuncs [NUM_FUNCS] = {
181 (CbCursFunc) macDoNull, GeneralCursor, macCursorTerm, macCursorTerm,
182 GeneralCursor, GeneralCursor
187 GetNhWin(WindowPtr mac_win) {
188 if (mac_win == _mt_window) /* term window is still maintained by both systems, and */
189 return theWindows; /* WRefCon still refers to tty struct, so we have to map it */
191 NhWindow *aWin = (NhWindow *)GetWRefCon (mac_win);
192 if (aWin >= theWindows && aWin < &theWindows[NUM_MACWINDOWS])
195 return ((NhWindow *) nil);
199 Boolean CheckNhWin (WindowPtr mac_win) {
200 return GetNhWin (mac_win) != nil;
205 AppleEventHandler (const AppleEvent* inAppleEvent, AppleEvent* outAEReply, long inRefCon) {
206 #if defined(__SC__) || defined(__MRC__)
207 # pragma unused(outAEReply,inRefCon)
215 err = AEGetAttributePtr (inAppleEvent, keyEventIDAttr, typeType, &typeCode,
216 &EventID, sizeof (EventID), &actualSize);
220 case kAEOpenApplication :
221 macFlags.gotOpen = 1;
223 case kAEPrintDocuments :
224 err = errAEEventNotHandled;
226 case kAEQuitApplication :
227 /* Flush key queue */
228 keyQueueCount = keyQueueWrite = keyQueueRead = 0;
229 AddToKeyQueue ('S', 1);
231 case kAEOpenDocuments : {
236 long index, itemsInList;
238 if((err = AEGetParamDesc(inAppleEvent, keyDirectObject, typeAEList, &docList)) != noErr ||
239 (err = AECountItems(&docList, &itemsInList)) != noErr){
240 if (err == errAEDescNotFound)
246 for(index = 1; index <= itemsInList; index++){
247 err = AEGetNthPtr(&docList, index, typeFSS, &keywd, &typeCode, (Ptr)&fss,
248 sizeof(FSSpec), &actualSize);
252 err = FSpGetFInfo (&fss, &fndrInfo);
256 if (fndrInfo.fdType != SAVE_TYPE)
257 continue; /* only look at save files */
259 process_openfile (fss.vRefNum, fss.parID, fss.name, fndrInfo.fdType);
260 if (macFlags.gotOpen)
261 break; /* got our save file */
263 err = AEDisposeDesc(&docList);
269 /* Check to see if all required parameters for this type of event are present */
271 err = AEGetAttributePtr (inAppleEvent, keyMissedKeywordAttr,
272 typeWildCard, &typeCode, NULL, 0, &actualSize);
273 if (err == errAEDescNotFound)
274 err = noErr; /* got all the required parameters */
275 else if (err == noErr) /* missed a required parameter */
276 err = errAEEventNotHandled;
283 short win_fonts [NHW_TEXT + 1];
292 #if !TARGET_API_MAC_CARBON
293 if (LMGetDefltStack() < 50 * 1024L) {
294 SetApplLimit ((void *) ((long) LMGetCurStackBase() - (50 * 1024L)));
297 for (i = 0; i < 5; i ++)
300 InitGraf (&qd.thePort);
308 memset (&macFlags, 0, sizeof(macFlags));
309 if (!Gestalt (gestaltOSAttr, & l)) {
310 macFlags.processes = (l & (1 << gestaltLaunchControl)) ? 1 : 0;
311 macFlags.tempMem = (l & (1 << gestaltRealTempMemory)) ? 1 : 0;
312 macFlags.hasDebugger = (l & (1 << gestaltSysDebuggerSupport)) ? 1 : 0;
314 if (!Gestalt (gestaltQuickdrawVersion, & l))
315 macFlags.color = (l >= gestalt8BitQD) ? 1 : 0;
317 if (!Gestalt (gestaltFindFolderAttr, & l))
318 macFlags.folders = (l & (1 << gestaltFindFolderPresent)) ? 1 : 0;
320 if (!Gestalt (gestaltHelpMgrAttr, & l))
321 macFlags.help = (l & (1 << gestaltHelpMgrPresent)) ? 1 : 0;
323 if (!Gestalt (gestaltFSAttr, & l))
324 macFlags.fsSpec = (l & (1 << gestaltHasFSSpecCalls)) ? 1 : 0;
326 if (!Gestalt (gestaltFontMgrAttr, & l))
327 macFlags.trueType = (l & (1 << gestaltOutlineFonts)) ? 1 : 0;
329 if (!Gestalt (gestaltAUXVersion, & l))
330 macFlags.aux = (l >= 0x200) ? 1 : 0;
332 if (!Gestalt (gestaltAliasMgrAttr, & l))
333 macFlags.alias = (l & (1 << gestaltAliasMgrPresent)) ? 1 : 0;
335 if (!Gestalt (gestaltStandardFileAttr, & l))
336 macFlags.standardFile = (l & (1 << gestaltStandardFile58)) ? 1 : 0;
338 gMouseRgn = NewRgn ();
340 GetQDGlobalsArrow(&qdarrow);
343 MoveScrollUPP = NewControlActionUPP(MoveScrollBar);
345 /* Set up base fonts for all window types */
346 GetFNum ("\pHackFont", &i);
349 win_fonts [NHW_BASE] = win_fonts [NHW_MAP] = win_fonts [NHW_STATUS] = i;
350 GetFNum ("\pPSHackFont", &i);
353 win_fonts [NHW_MESSAGE] = i;
354 win_fonts [NHW_TEXT] = kFontIDGeneva;
357 if(!Gestalt(gestaltAppleEventsAttr, &l) && (l & (1L << gestaltAppleEventsPresent))){
358 if (AEInstallEventHandler (kCoreEventClass, typeWildCard,
359 NewAEEventHandlerUPP(AppleEventHandler),
365 #if TARGET_API_MAC_CARBON
366 HGetVol(volName, &theDirs.dataRefNum, &theDirs.dataDirID);
369 * We should try to get this data from a rsrc, in the profile file
370 * the user double-clicked... This data should be saved with the
371 * save file in the resource fork, AND be saveable in "stationary"
373 GetVol (volName, &theDirs.dataRefNum );
374 GetWDInfo (theDirs.dataRefNum, &theDirs.dataRefNum, &theDirs.dataDirID, &l);
376 if (volName [0] > 31) volName [0] = 31;
377 for (l = 1; l <= volName [0]; l++) {
378 if (volName [l] == ':') {
384 BlockMove (volName, theDirs.dataName, l);
385 BlockMove (volName, theDirs.saveName, l);
386 BlockMove (volName, theDirs.levelName, l);
387 theDirs.saveRefNum = theDirs.levelRefNum = theDirs.dataRefNum;
388 theDirs.saveDirID = theDirs.levelDirID = theDirs.dataDirID;
390 /* Create the "record" file, if necessary */
391 check_recordfile("");
397 * Change default window fonts.
400 set_tty_font_name (int window_type, char *font_name) {
404 if (window_type < NHW_BASE || window_type > NHW_TEXT)
405 return general_failure;
407 C2P (font_name, new_font);
408 GetFNum (new_font, &(fnum));
410 return general_failure;
411 win_fonts [window_type] = fnum;
417 DrawScrollbar (NhWindow *aWin)
419 WindowPtr theWindow = aWin->its_window;
422 short val, lin, win_height;
425 if (!aWin->scrollBar)
427 GetControlBounds(aWin->scrollBar, &crect);
428 GetWindowBounds(aWin->its_window, kWindowContentRgn, &wrect);
429 OffsetRect(&wrect, -wrect.left, -wrect.top);
430 win_height = wrect.bottom - wrect.top;
432 if (crect.top != wrect.top - 1 ||
433 crect.left != wrect.right - SBARWIDTH) {
434 MoveControl (aWin->scrollBar, wrect.right - SBARWIDTH, wrect.top - 1);
436 if (crect.bottom != wrect.bottom - SBARHEIGHT ||
437 crect.right != wrect.right + 1) {
438 SizeControl (aWin->scrollBar, SBARWIDTH+1, win_height - SBARHEIGHT + 2);
440 vis = (win_height > (50 + SBARHEIGHT));
441 if (vis != IsControlVisible(aWin->scrollBar)) {
442 /* current status != control */
443 if (vis)/* if visible, show */
444 ShowControl (aWin->scrollBar);
446 HideControl (aWin->scrollBar);
449 if (aWin == theWindows + WIN_MESSAGE) {
450 /* calculate how big scroll bar is for message window */
451 lin -= (win_height - SBARHEIGHT) / aWin->row_height;
454 val = 0; /* always have message scrollbar active */
457 /* calculate how big scroll bar is for other windows */
458 lin -= win_height / aWin->row_height;
461 if (lin) val = 0; /* if there are 1+ screen lines, activate scrollbar */
462 else val = 255; /* else grey it out */
464 SetControlMaximum (aWin->scrollBar, lin);
465 HiliteControl (aWin->scrollBar, val);
466 val = GetControlValue (aWin->scrollBar);
467 if (val != aWin->scrollPos) {
468 InvalWindowRect(theWindow, &wrect);
469 aWin->scrollPos = val;
474 #define MAX_HEIGHT 100
475 #define MIN_HEIGHT 50
476 #define MIN_WIDTH 300
479 * This function could be overloaded with any amount of intelligence...
484 #if TARGET_API_MAC_CARBON
485 ConstrainWindowToScreen(_mt_window, kWindowStructureRgn,
486 kWindowConstrainMoveRegardlessOfFit, NULL, NULL);
488 short left, top, width, height;
489 int ix, numText = 0, numMenu = 0;
490 int mbar_height = GetMBarHeight();
497 screenArea = GetQDGlobalsScreenBits(&qbitmap)->bounds;
498 OffsetRect (&screenArea, - screenArea.left, - screenArea.top);
501 height = _mt_window->portRect.bottom - _mt_window->portRect.top;
502 width = _mt_window->portRect.right - _mt_window->portRect.left;
504 if (!RetrievePosition (kMapWindow, &top, &left)) {
505 top = mbar_height + (small_screen ? 2 : 20);
506 left = (screenArea.right - width) / 2;
508 MoveWindow (_mt_window, left, top, 1);
511 if (!RetrievePosition (kMessageWindow, &top, &left)) {
517 if (!RetrieveSize (kMessageWindow, top, left, &height, &width)) {
518 height = screenArea.bottom - top - (small_screen ? 2-SBARHEIGHT : 2);
519 if (height > MAX_HEIGHT) {
521 } else if (height < MIN_HEIGHT) {
524 left = screenArea.right - width;
525 top = screenArea.bottom - MIN_HEIGHT;
529 /* Move these windows */
530 nhWin = theWindows + WIN_MESSAGE;
531 theWindow = nhWin->its_window;
533 MoveWindow (theWindow, left, top, 1);
534 SizeWindow (theWindow, width, height, 1);
535 if (nhWin->scrollBar)
536 DrawScrollbar (nhWin);
538 /* Handle other windows */
539 for (ix = 0; ix < NUM_MACWINDOWS; ix ++) {
540 if (ix != WIN_STATUS && ix != WIN_MESSAGE && ix != WIN_MAP && ix != BASE_WINDOW) {
541 theWindow = theWindows [ix].its_window;
542 if (theWindow && ((WindowPeek) theWindow)->visible) {
544 if (((WindowPeek)theWindow)->windowKind == WIN_BASE_KIND + NHW_MENU) {
545 if (!RetrievePosition (kMenuWindow, &top, &left)) {
546 top = mbar_height * 2;
549 top += (numMenu * mbar_height);
553 if (!RetrievePosition (kTextWindow, &top, &left)) {
554 top = mbar_height * 2;
555 left = screenArea.right - 3 -
556 (theWindow->portRect.right - theWindow->portRect.left);
558 top += (numText * mbar_height);
562 while (top > screenArea.bottom - MIN_HEIGHT) {
563 top -= screenArea.bottom - mbar_height * 2;
566 MoveWindow (theWindow, left, top, 1);
576 mac_create_nhwindow (int kind) {
581 if (kind < NHW_BASE || kind > NHW_TEXT) {
582 error ("cre_win: Invalid kind %d.", kind);
586 for (i = 0; i < NUM_MACWINDOWS; i ++) {
587 if (!theWindows [i].its_window)
590 if (i >= NUM_MACWINDOWS) {
591 error ("cre_win: Win full; freeing extras");
592 for (i = 0; i < NUM_MACWINDOWS; i ++) {
593 if (IsWindowVisible(theWindows [i].its_window) || i == WIN_INVEN ||
594 GetWindowKind(theWindows [i].its_window) != WIN_BASE_KIND + NHW_MENU &&
595 GetWindowKind(theWindows [i].its_window) != WIN_BASE_KIND + NHW_TEXT)
597 mac_destroy_nhwindow(i);
600 error ("cre_win: Out of ids!");
605 aWin = &theWindows [i];
606 aWin->windowTextLen = 0L;
607 aWin->scrollBar = (ControlHandle) 0;
609 aWin->menuSelected = 0;
612 aWin->menuChar = 'a';
614 dprintf ("cre_win: New kind %d", kind);
616 if (kind == NHW_BASE || kind == NHW_MAP || kind == NHW_STATUS) {
617 short x_sz, x_sz_p, y_sz, y_sz_p;
618 if (kind != NHW_BASE) {
619 if (i != tty_create_nhwindow(kind)) {
620 dprintf ("cre_win: error creating kind %d", kind);
622 if (kind == NHW_MAP) {
623 wins[i]->offy = 0; /* the message box is in a separate window */
626 aWin->its_window = _mt_window;
627 get_tty_metrics(aWin->its_window, &x_sz, &y_sz, &x_sz_p, &y_sz_p,
628 &aWin->font_number, &aWin->font_size,
629 &aWin->char_width, &aWin->row_height);
633 aWin->its_window = GetNewWindow (WIN_BASE_RES + kind, (WindowPtr) 0L, (WindowPtr) -1L);
634 SetWindowKind(aWin->its_window, WIN_BASE_KIND + kind);
635 SetWRefCon(aWin->its_window, (long) aWin);
636 if (!(aWin->windowText = NewHandle (TEXT_BLOCK))) {
637 error ("cre_win: NewHandle fail(%ld)", (long) TEXT_BLOCK);
638 DisposeWindow (aWin->its_window);
639 aWin->its_window = (WindowPtr) 0;
642 aWin->x_size = aWin->y_size = 0;
643 aWin->x_curs = aWin->y_curs = 0;
645 mac_clear_nhwindow (i);
647 SetPortWindowPort(aWin->its_window);
649 if (kind == NHW_MESSAGE) {
650 aWin->font_number = win_fonts [NHW_MESSAGE];
651 aWin->font_size = iflags.wc_fontsiz_message? iflags.wc_fontsiz_message :
652 iflags.large_font ? 12 : 9;
654 const Rect out_of_scr = {10000, 10000, 10100, 10100};
655 TextFont(aWin->font_number);
656 TextSize(aWin->font_size);
658 top_line = TENew(&out_of_scr, &out_of_scr);
659 TEActivate(top_line);
663 aWin->font_number = win_fonts [NHW_TEXT];
664 aWin->font_size = iflags.wc_fontsiz_text ? iflags.wc_fontsiz_text : 9;
667 TextFont (aWin->font_number);
668 TextSize (aWin->font_size);
671 aWin->ascent_height = fi.ascent + fi.leading;
672 aWin->row_height = aWin->ascent_height + fi.descent;
673 aWin->char_width = fi.widMax;
675 if (kind == NHW_MENU || kind == NHW_TEXT || kind == NHW_MESSAGE) {
678 GetWindowBounds(aWin->its_window, kWindowContentRgn, &r);
679 r.right -= (r.left - 1);
680 r.left = r.right - SBARWIDTH;
681 r.bottom -= (r.top + SBARHEIGHT);
683 aWin->scrollBar = NewControl (aWin->its_window, &r, "\p", (r.bottom > r.top + 50), 0, 0, 0, 16, 0L);
691 mac_init_nhwindows (int *argcp, char **argv)
693 #if !TARGET_API_MAC_CARBON
694 Rect scr = (*GetGrayRgn())->rgnBBox;
695 small_screen = scr.bottom - scr.top <= (iflags.large_font ? 12*40 : 9*40);
702 theWindows = (NhWindow *) NewPtrClear (NUM_MACWINDOWS * sizeof (NhWindow));
704 error("mac_init_nhwindows: Couldn't allocate memory for windows.");
708 tty_init_nhwindows(argcp, argv);
709 iflags.window_inited = TRUE;
711 /* Some ugly hacks to make both interfaces happy:
712 * Mac port uses both tty interface (for main map) and extra windows. The winids need to
713 * be kept in synch for both interfaces to map. Also, the "blocked" display_nhwindow case
714 * for the map automatically calls the tty interface for the message box, so some version
715 * of the message box has to exist in the tty world to prevent a meltdown, even though most
716 * messages are handled in mac window.
718 mac_create_nhwindow(NHW_BASE);
719 tty_create_nhwindow(NHW_MESSAGE);
720 RetrievePosition(kMessageWindow, &r.top, &r.left);
721 RetrieveSize(kMessageWindow, r.top, r.left, &r.bottom, &r.right);
722 MoveWindow(theWindows[NHW_MESSAGE].its_window, r.left, r.top, false);
723 SizeWindow(theWindows[NHW_MESSAGE].its_window, r.right, r.bottom, true);
724 ConstrainWindowToScreen(theWindows[NHW_MESSAGE].its_window, kWindowStructureRgn,
725 kWindowConstrainMoveRegardlessOfFit, NULL, NULL);
731 mac_clear_nhwindow (winid win) {
734 NhWindow *aWin = &theWindows [win];
735 WindowPtr theWindow = aWin->its_window;
737 if (win < 0 || win >= NUM_MACWINDOWS || !theWindow) {
738 error ("clr_win: Invalid win %d.", win);
741 if (theWindow == _mt_window) {
742 tty_clear_nhwindow(win);
748 SetPortWindowPort(theWindow);
749 GetWindowBounds(theWindow, kWindowContentRgn, &r);
750 OffsetRect(&r, -r.left, -r.top);
752 r.right -= SBARWIDTH;
754 switch (GetWindowKind(theWindow) - WIN_BASE_KIND) {
756 if (aWin->scrollPos == aWin->y_size - 1) /* if no change since last clear */
757 return; /* don't bother with redraw */
758 r.bottom -= SBARHEIGHT;
759 for (l = 0; aWin->y_size > iflags.msg_history;) {
760 const char cr = CHAR_CR;
761 l = Munger(aWin->windowText, l, &cr, 1, nil, 0) + 1;
765 aWin->windowTextLen -= l;
766 BlockMove(*aWin->windowText + l, *aWin->windowText, aWin->windowTextLen);
768 aWin->last_more_lin = aWin->y_size;
769 aWin->save_lin = aWin->y_size;
770 aWin->scrollPos = aWin->y_size ? aWin->y_size - 1 : 0;
773 if (aWin->menuInfo) {
774 DisposeHandle((Handle)aWin->menuInfo);
775 aWin->menuInfo = NULL;
777 if (aWin->menuSelected) {
778 DisposeHandle((Handle)aWin->menuSelected);
779 aWin->menuSelected = NULL;
781 aWin->menuChar = 'a';
787 SetHandleSize (aWin->windowText, TEXT_BLOCK);
788 aWin->windowTextLen = 0L;
794 if (aWin->scrollBar) {
795 SetControlMaximum (aWin->scrollBar, aWin->y_size);
796 SetControlValue(aWin->scrollBar, aWin->scrollPos);
801 InvalWindowRect(theWindow, &r);
806 ClosingWindowChar(const int c) {
807 return c == CHAR_ESC || c == CHAR_BLANK || c == CHAR_LF || c == CHAR_CR ||
818 GetWindowBounds(theWindows[WIN_MESSAGE].its_window, kWindowContentRgn, &rect);
819 OffsetRect(&rect, -rect.left, -rect.top);
820 return (WIN_MESSAGE != WIN_ERR && top_line &&
821 (*top_line)->viewRect.left < rect.right);
827 #define BTN_H (SBARHEIGHT-3)
830 topl_resp_rect(int resp_idx, Rect *r)
835 GetWindowBounds(theWindows[WIN_MESSAGE].its_window, kWindowContentRgn, &rect);
836 OffsetRect(&rect, -rect.left, -rect.top);
837 r->left = (BTN_IND + BTN_W) * resp_idx + BTN_IND;
838 r->right = r->left + BTN_W;
839 r->bottom = rect.bottom - 1;
840 r->top = r->bottom - BTN_H;
846 enter_topl_mode(char *query) {
850 putstr(WIN_MESSAGE, ATR_BOLD, query);
852 topl_query_len = strlen(query);
853 (*top_line)->selStart = topl_query_len;
854 (*top_line)->selEnd = topl_query_len;
855 (*top_line)->viewRect.left = 0;
856 PtrToXHand(query, (*top_line)->hText, topl_query_len);
860 mac_display_nhwindow(WIN_MESSAGE, FALSE);
865 leave_topl_mode(char *answer) {
866 unsigned char *ap, *bp;
868 int ans_len = (*top_line)->teLength - topl_query_len;
869 NhWindow *aWin = theWindows + WIN_MESSAGE;
874 /* Cap length of reply */
875 if (ans_len >= BUFSZ)
878 /* remove unprintables from the answer */
879 for (ap = *(*top_line)->hText + topl_query_len, bp = answer; ans_len > 0; ans_len--, ap++) {
880 if (*ap >= ' ' && *ap < 128) {
886 if (aWin->windowTextLen && (*aWin->windowText)[aWin->windowTextLen-1] == CHAR_CR) {
887 -- aWin->windowTextLen;
890 putstr(WIN_MESSAGE, ATR_BOLD, answer);
892 (*top_line)->viewRect.left += 10000;
897 * TESetSelect flushes out all the pending key strokes. I hate it.
900 topl_set_select(short selStart, short selEnd) {
901 TEDeactivate(top_line);
902 (*top_line)->selStart = selStart;
903 (*top_line)->selEnd = selEnd;
904 TEActivate(top_line);
909 topl_replace(char *new_ans) {
910 topl_set_select(topl_query_len, (*top_line)->teLength);
912 TEInsert(new_ans, strlen(new_ans), top_line);
917 topl_key(unsigned char ch, Boolean ext) {
920 topl_replace("\x1b");
921 case CHAR_ENTER: case CHAR_CR: case CHAR_LF:
925 mac_doprev_message();
927 case '\x1e'/* up arrow */:
930 case CHAR_BS: case '\x1c'/* left arrow */:
931 if ((*top_line)->selEnd <= topl_query_len)
940 int com_index = -1, oindex = 0;
941 while(extcmdlist[oindex].ef_txt != (char *)0) {
942 if(!strncmpi(*(*top_line)->hText + topl_query_len,
943 extcmdlist[oindex].ef_txt,
944 (*top_line)->teLength - topl_query_len)) {
945 if(com_index == -1) /* No matches yet*/
947 else /* More than 1 match */ {
955 topl_replace((char *) extcmdlist[com_index].ef_txt);
963 topl_flash_resp(int resp_idx) {
964 unsigned long dont_care;
966 SetPortWindowPort(theWindows[WIN_MESSAGE].its_window);
967 topl_resp_rect(resp_idx, &frame);
968 InsetRect(&frame, 1, 1);
970 Delay(GetDblTime() / 2, &dont_care);
976 topl_set_def(int new_def_idx) {
978 SetPortWindowPort(theWindows[WIN_MESSAGE].its_window);
979 topl_resp_rect(topl_def_idx, &frame);
980 InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame);
981 topl_def_idx = new_def_idx;
982 topl_resp_rect(new_def_idx, &frame);
983 InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame);
988 topl_set_resp(char *resp, char def) {
994 const char any_str[2] = {CHAR_ANY, '\0'};
995 resp = (char *) any_str;
999 SetPortWindowPort(theWindows[WIN_MESSAGE].its_window);
1000 r_len1 = strlen(resp);
1001 r_len = strlen(topl_resp);
1004 topl_resp_rect(0, &frame);
1005 frame.right = (BTN_IND + BTN_W) * r_len;
1006 InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame);
1008 strcpy(topl_resp, resp);
1009 loc = strchr (resp, def);
1010 topl_def_idx = loc ? loc - resp : -1;
1015 topl_resp_key(char ch) {
1016 if (strlen(topl_resp) > 0) {
1017 char *loc = strchr(topl_resp, ch);
1020 if (ch == '\x9'/* tab */) {
1021 topl_set_def(topl_def_idx<=0 ? strlen(topl_resp)-1 : topl_def_idx-1);
1023 } else if (ch == CHAR_ESC) {
1024 loc = strchr(topl_resp, 'q');
1026 loc = strchr(topl_resp, 'n');
1027 if (!loc && topl_def_idx >= 0)
1028 loc = topl_resp + topl_def_idx;
1030 } else if (ch == (0x1f & 'P')) {
1031 mac_doprev_message();
1033 } else if (topl_def_idx >= 0) {
1034 if (ch == CHAR_ENTER || ch == CHAR_CR || ch == CHAR_LF ||
1035 ch == CHAR_BLANK || topl_resp[topl_def_idx] == CHAR_ANY)
1036 loc = topl_resp + topl_def_idx;
1038 else if (strchr(topl_resp, '#')) {
1040 topl_set_def(strchr(topl_resp, '#') - topl_resp);
1041 TEKey(ch, top_line);
1044 } else if (topl_resp[topl_def_idx] == '#') {
1045 if (ch == '\x1e'/* up arrow */) {
1046 topl_set_select(topl_query_len, topl_query_len);
1048 } else if (ch == '\x1d'/* right arrow */ ||
1049 ch == '\x1f'/* down arrow */ ||
1050 ch == CHAR_BS || ch == '\x1c'/* left arrow */ &&
1051 (*top_line)->selEnd > topl_query_len) {
1052 TEKey(ch, top_line);
1061 topl_flash_resp(loc - topl_resp);
1062 if (*loc != CHAR_ANY)
1064 TEKey(ch, top_line);
1073 adjust_window_pos(NhWindow *aWin, short width, short height)
1075 WindowRef theWindow = aWin->its_window;
1076 #if TARGET_API_MAC_CARBON
1080 GetWindowBounds(theWindow, kWindowContentRgn, &r);
1081 RetrieveWinPos(theWindow, &r.top, &r.left);
1082 MoveWindow(theWindow, r.left, r.top, false);
1083 SizeWindow(theWindow, width, height, true);
1084 ConstrainWindowToScreen(theWindow, kWindowStructureRgn,
1085 kWindowConstrainMoveRegardlessOfFit, NULL, NULL);
1087 Rect scr_r = (*GetGrayRgn())->rgnBBox;
1088 const Rect win_ind = {2, 2, 3, 3};
1089 const short min_w = theWindow->portRect.right - theWindow->portRect.left,
1090 max_w = scr_r.right - scr_r.left - win_ind.left - win_ind.right;
1094 SetPortWindowPort(theWindow);
1095 if (!RetrieveWinPos(theWindow, &pos.v, &pos.h)) {
1096 pos.v = 0; /* take window's existing position */
1098 LocalToGlobal(&pos);
1101 max_h = scr_r.bottom - win_ind.bottom - pos.v;
1102 if (height > max_h) height = max_h;
1103 if (height < MIN_HEIGHT) height = MIN_HEIGHT;
1104 if (width < min_w) width = min_w;
1105 if (width > max_w) width = max_w;
1106 SizeWindow(theWindow, width, height, true);
1108 if (pos.v + height + win_ind.bottom > scr_r.bottom)
1109 pos.v = scr_r.bottom - height - win_ind.bottom;
1110 if (pos.h + width + win_ind.right > scr_r.right)
1111 pos.h = scr_r.right - width - win_ind.right;
1112 MoveWindow(theWindow, pos.h, pos.v, false);
1113 if (aWin->scrollBar)
1114 DrawScrollbar (aWin);
1121 * display/select/update the window.
1122 * If f is true, this window should be "modal" - don't return
1123 * until presumed seen.
1126 mac_display_nhwindow (winid win, BOOLEAN_P f) {
1127 NhWindow *aWin = &theWindows [win];
1128 WindowPtr theWindow = aWin->its_window;
1130 if (win < 0 || win >= NUM_MACWINDOWS || !theWindow) {
1131 error ("disp_win: Invalid window %d.", win);
1135 if (theWindow == _mt_window) {
1136 tty_display_nhwindow(win, f);
1140 if (f && inSelect == WIN_ERR && win == WIN_MESSAGE) {
1141 topl_set_resp ((char *)0, 0);
1142 if (aWin->windowTextLen > 0 &&
1143 (*aWin->windowText) [aWin->windowTextLen - 1] == CHAR_CR) {
1144 -- aWin->windowTextLen;
1147 putstr (win, flags.standout ? ATR_INVERSE : ATR_NONE, " --More--");
1150 if (!IsWindowVisible(theWindow)) {
1151 if (win != WIN_MESSAGE)
1152 adjust_window_pos(aWin, aWin->x_size + SBARWIDTH+1, aWin->y_size *aWin->row_height);
1154 SelectWindow (theWindow);
1155 ShowWindow (theWindow);
1158 if (f && inSelect == WIN_ERR) {
1164 ch = mac_nhgetch ();
1165 } while (!ClosingWindowChar (ch));
1169 if (win == WIN_MESSAGE)
1170 topl_set_resp ("", '\0');
1172 HideWindow (theWindow);
1179 mac_destroy_nhwindow (winid win) {
1180 WindowPtr theWindow;
1181 NhWindow *aWin = &theWindows [win];
1184 if (win < 0 || win >= NUM_MACWINDOWS) {
1185 if (iflags.window_inited) error ("dest_win: Invalid win %d.", win);
1188 theWindow = aWin->its_window;
1190 error ("dest_win: Not allocated win %d.", win);
1195 * Check special windows. The base window should never go away.
1196 * Other "standard" windows should not go away unless we've exitted nhwindows.
1198 if (theWindow == _mt_window) {
1201 if (win == WIN_INVEN || win == WIN_MESSAGE) {
1202 if (iflags.window_inited) {
1203 if (flags.tombstone && killer) {
1204 /* Prepare for the coming of the tombstone window. */
1205 win_fonts [NHW_TEXT] = kFontIDMonaco;
1209 if (win == WIN_MESSAGE)
1210 WIN_MESSAGE = WIN_ERR;
1213 kind = GetWindowKind(theWindow) - WIN_BASE_KIND;
1215 if ((!IsWindowVisible(theWindow) || (kind != NHW_MENU && kind != NHW_TEXT))) {
1216 DisposeWindow (theWindow);
1217 if (aWin->windowText) {
1218 DisposeHandle(aWin->windowText);
1220 aWin->its_window = (WindowPtr) 0;
1221 aWin->windowText = (Handle) 0;
1227 mac_number_pad (int pad) {
1228 iflags.num_pad = pad;
1233 trans_num_keys(EventRecord *theEvent) {
1234 #if defined(__SC__) || defined(__MRC__)
1235 # pragma unused(theEvent)
1237 /* KMH -- Removed this translation.
1238 * Number pad keys should always emit digit characters.
1239 * That's consistent with the default MacOS behavior.
1240 * The number_pad option controls how digits are interpreted.
1243 if (iflags.num_pad) {
1244 Handle h = GetResource('Nump', theEvent->modifiers & shiftKey ? 129 : 128);
1246 short inkey = (theEvent->message & keyCodeMask), *ab = (short *)*h;
1249 if (inkey == (ab[i] & keyCodeMask)) {
1250 theEvent->message = ab[i];
1261 * Note; theWindow may very well be null here, since keyDown may call
1262 * it when theres no window !!!
1265 GeneralKey (EventRecord *theEvent, WindowPtr theWindow) {
1266 #if defined(__SC__) || defined(__MRC__)
1267 # pragma unused(theWindow)
1270 trans_num_keys (theEvent);
1272 AddToKeyQueue (topl_resp_key (theEvent->message & 0xff), TRUE);
1277 * Routine used to select and de-select elements in a menu window, used by KeyMenu,
1278 * ClickMenu, and UpdateMenu. Takes the NhWindow and a line ref relative to the scrollbar.
1280 static void ToggleMenuSelect (NhWindow *aWin, int line) {
1284 GetWindowBounds(aWin->its_window, kWindowContentRgn, &r);
1285 OffsetRect(&r, -r.left, -r.top);
1286 if (aWin->scrollBar)
1287 r.right -= SBARWIDTH;
1288 r.top = line * aWin->row_height;
1289 r.bottom = r.top + aWin->row_height;
1291 LMSetHiliteMode((UInt8) (LMGetHiliteMode() & 0x7F));
1296 * Check to see if given item is selected, return index if it is
1299 ListItemSelected (NhWindow *aWin, int item) {
1302 HLock ((char**)aWin->menuSelected);
1303 /* Find item in selection list */
1304 for (i = aWin->miSelLen - 1; i >= 0; i--) {
1305 if ((*aWin->menuSelected) [i] == item)
1308 HUnlock ((char**)aWin->menuSelected);
1313 * Add item to selection list if it's not selected already
1314 * If it is selected already, remove it from the list.
1317 ToggleMenuListItemSelected (NhWindow *aWin, short item) {
1318 int i = ListItemSelected (aWin, item);
1320 HLock ((char**)aWin->menuSelected);
1321 if (i < 0) { /* not there, so add */
1322 (*aWin->menuSelected) [aWin->miSelLen] = item;
1325 else { /* there, so remove */
1326 short *mi = &(*aWin->menuSelected)[i];
1328 memcpy (mi, mi + 1, (aWin->miSelLen - i)*sizeof(short));
1330 HUnlock ((char**)aWin->menuSelected);
1335 * Find menu item in list given a line number on the window
1338 ListCoordinateToItem (NhWindow *aWin, short Row) {
1342 HLock ((char**)aWin->menuInfo);
1343 for (i = 0, mi = *aWin->menuInfo; i < aWin->miLen; i++, mi++) {
1344 if (mi->line == Row + aWin->scrollPos) {
1349 HUnlock ((char**)aWin->menuInfo);
1355 macKeyMenu (EventRecord *theEvent, WindowPtr theWindow) {
1356 NhWindow *aWin = GetNhWin(theWindow);
1358 int l, ch = theEvent->message & 0xff;
1360 if (aWin && aWin->menuInfo) {
1361 HLock ((char**)aWin->menuInfo);
1362 for (l = 0, mi = *aWin->menuInfo; l < aWin->miLen; l++, mi++) {
1363 if (mi->accelerator == ch) {
1364 ToggleMenuListItemSelected (aWin, l);
1365 if (mi->line >= aWin->scrollPos && mi->line <= aWin->y_size) {
1366 SetPortWindowPort(theWindow);
1367 ToggleMenuSelect (aWin, mi->line - aWin->scrollPos);
1369 /* Dismiss window if only picking one item */
1370 if (aWin->how != PICK_ANY)
1371 AddToKeyQueue(CHAR_CR, 1);
1375 HUnlock ((char**)aWin->menuInfo);
1376 /* add key if didn't find it in menu and not filtered */
1377 if (l == aWin->miLen && filter_scroll_key (ch, aWin))
1378 GeneralKey (theEvent, theWindow);
1384 macClickMenu (EventRecord *theEvent, WindowRef theWindow) {
1386 NhWindow *aWin = GetNhWin(theWindow);
1390 GetWindowBounds(theWindow, kWindowContentRgn, &wrect);
1391 OffsetRect(&wrect, -wrect.left, -wrect.top);
1392 if (aWin->scrollBar && IsControlVisible(aWin->scrollBar)) {
1394 ControlHandle theBar;
1396 p = theEvent->where;
1398 code = FindControl (p, theWindow, &theBar);
1400 DoScrollBar (p, code, theBar, aWin);
1404 if (inSelect != WIN_ERR && aWin->how != PICK_NONE) {
1405 short currentRow = -1, previousRow = -1;
1406 short previousItem = -1, item = -1;
1407 Boolean majorSelectState, firstRow = TRUE;
1410 #if !TARGET_API_MAC_CARBON
1414 currentRow = p.v / aWin->row_height;
1415 if (p.h < wrect.left || p.h > wrect.right ||
1416 p.v < 0 || p.v > wrect.bottom || currentRow >= aWin->y_size) {
1417 continue; /* not in window range */
1420 item = ListCoordinateToItem (aWin, currentRow);
1422 if (item != previousItem) {
1423 /* Implement typical Mac multiple-selection behavior
1424 * (ie, not the UI implemented by the Finder)
1426 Boolean itemIsSelected = (ListItemSelected (aWin,item) >= 0);
1429 /* this is first valid row, so major state is opposite of what this row is */
1430 majorSelectState = !itemIsSelected;
1434 if (aWin->how == PICK_ONE && previousItem != -1) {
1435 /* if previous row was selected and we're only selecting one object,
1436 * deselect previous row!
1438 ToggleMenuListItemSelected (aWin, previousItem);
1439 ToggleMenuSelect (aWin, previousRow);
1444 continue; /* header line */
1446 if (majorSelectState != itemIsSelected) {
1447 ToggleMenuListItemSelected (aWin, item);
1448 ToggleMenuSelect (aWin, currentRow);
1451 previousRow = currentRow;
1452 previousItem = item;
1454 } while (StillDown ());
1456 /* Dismiss window if only picking one item */
1457 if (aWin->how == PICK_ONE)
1458 AddToKeyQueue(CHAR_CR, 1);
1464 macKeyText (EventRecord *theEvent, WindowPtr theWindow) {
1465 NhWindow *aWin = GetNhWin (theWindow);
1466 char c = filter_scroll_key (theEvent->message & 0xff, aWin);
1468 if (inSelect == WIN_ERR && ClosingWindowChar (c)) {
1469 HideWindow (theWindow);
1470 mac_destroy_nhwindow (aWin - theWindows);
1472 GeneralKey (theEvent, theWindow);
1479 macClickText (EventRecord *theEvent, WindowPtr theWindow) {
1480 NhWindow *aWin = GetNhWin (theWindow);
1482 if (aWin->scrollBar && IsControlVisible(aWin->scrollBar)) {
1484 Point p = theEvent->where;
1485 ControlHandle theBar;
1488 code = FindControl (p, theWindow, &theBar);
1490 DoScrollBar (p, code, theBar, aWin);
1497 macClickMessage (EventRecord *theEvent, WindowPtr theWindow) {
1499 Point mouse = theEvent->where;
1501 GlobalToLocal(&mouse);
1502 while (topl_resp[r_idx]) {
1504 topl_resp_rect(r_idx, &frame);
1505 InsetRect(&frame, 1, 1);
1506 if (PtInRect(mouse, &frame)) {
1507 Boolean in_btn = true;
1510 while (WaitMouseUp()) {
1511 #if !TARGET_API_MAC_CARBON
1515 if (PtInRect(mouse, &frame) != in_btn) {
1522 AddToKeyQueue (topl_resp [r_idx], 1);
1530 macClickText(theEvent, theWindow);
1535 macClickTerm (EventRecord *theEvent, WindowPtr theWindow) {
1536 NhWindow *nhw = GetNhWin(theWindow);
1537 Point where = theEvent->where;
1539 GlobalToLocal(&where);
1540 where.h = where.h / nhw->char_width + 1;
1541 where.v = where.v / nhw->row_height;
1542 clicked_mod = (theEvent->modifiers & shiftKey) ? CLICK_2 : CLICK_1;
1544 if (strchr(topl_resp, *click_to_cmd(where.h, where.v, clicked_mod)))
1547 #if !TARGET_API_MAC_CARBON
1549 while (WaitMouseUp())
1553 gClickedToMove = TRUE;
1554 clicked_pos = where;
1559 MoveScrollBar (ControlHandle theBar, short part) {
1563 int now, amtToScroll;
1565 NhWindow *winToScroll;
1570 theWin = GetControlOwner(theBar);
1571 GetWindowBounds(theWin, kWindowContentRgn, &r);
1572 OffsetRect(&r, -r.left, -r.top);
1573 winToScroll = (NhWindow*)(GetWRefCon(theWin));
1574 now = GetControlValue (theBar);
1576 if (part == kControlPageUpPart || part == kControlPageDownPart)
1577 amtToScroll = (r.bottom - r.top) / winToScroll->row_height;
1581 if (part == kControlPageUpPart || part == kControlUpButtonPart) {
1582 int bound = GetControlMinimum (theBar);
1583 if (now - bound < amtToScroll)
1584 amtToScroll = now - bound;
1585 amtToScroll = -amtToScroll;
1587 int bound = GetControlMaximum (theBar);
1588 if (bound - now < amtToScroll)
1589 amtToScroll = bound - now;
1595 SetControlValue (theBar, now + amtToScroll);
1596 winToScroll->scrollPos = now + amtToScroll;
1597 r.right -= SBARWIDTH;
1598 if (winToScroll == theWindows + WIN_MESSAGE)
1599 r.bottom -= SBARHEIGHT;
1601 ScrollRect (&r, 0, -amtToScroll * winToScroll->row_height, rgn);
1603 InvalWindowRgn(theWin, rgn);
1604 BeginUpdate(theWin);
1606 winUpdateFuncs [GetWindowKind(theWin) - WIN_BASE_KIND] (&fake, theWin);
1615 DoScrollBar (Point p, short code, ControlHandle theBar, NhWindow *aWin)
1617 ControlActionUPP func = NULL;
1620 if (code == kControlUpButtonPart || code == kControlPageUpPart ||
1621 code == kControlDownButtonPart || code == kControlPageDownPart)
1622 func = MoveScrollUPP;
1623 (void) TrackControl(theBar, p, func);
1625 if (aWin->scrollPos != GetControlValue (theBar)) {
1626 aWin->scrollPos = GetControlValue (theBar);
1627 GetWindowBounds(aWin->its_window, kWindowContentRgn, &rect);
1628 OffsetRect(&rect, -rect.left, -rect.top);
1629 InvalWindowRect(aWin->its_window, &rect);
1636 filter_scroll_key(const int ch, NhWindow *aWin) {
1637 if (aWin->scrollBar && GetControlValue(aWin->scrollBar) < GetControlMaximum(aWin->scrollBar)) {
1639 if (ch == CHAR_BLANK) {
1640 part = kControlPageDownPart;
1642 else if (ch == CHAR_CR || ch == CHAR_LF) {
1643 part = kControlDownButtonPart;
1646 SetPortWindowPort(aWin->its_window);
1647 MoveScrollBar(aWin->scrollBar, part);
1656 mac_doprev_message(void) {
1658 NhWindow *winToScroll = &theWindows[WIN_MESSAGE];
1659 mac_display_nhwindow(WIN_MESSAGE, FALSE);
1660 SetPortWindowPort(winToScroll->its_window);
1661 MoveScrollBar(winToScroll->scrollBar, kControlUpButtonPart);
1668 macDoNull (EventRecord *theEvent, WindowPtr theWindow) {
1674 draw_growicon_vert_only(WindowPtr wind)
1677 RgnHandle org_clip = NewRgn();
1681 SetPortWindowPort(wind);
1683 GetWindowBounds(wind, kWindowContentRgn, &r);
1684 OffsetRect(&r, -r.left, -r.top);
1685 r.left = r.right - SBARWIDTH;
1689 DisposeRgn(org_clip);
1695 macUpdateMessage (EventRecord *theEvent, WindowPtr theWindow)
1697 RgnHandle org_clip = NewRgn(), clip = NewRgn();
1699 NhWindow *aWin = GetNhWin(theWindow);
1706 GetWindowBounds(theWindow, kWindowContentRgn, &r);
1707 OffsetRect(&r, -r.left, -r.top);
1709 DrawControls(theWindow);
1710 DrawGrowIcon(theWindow);
1712 for (l = 0; topl_resp[l]; l++) {
1714 unsigned char tmp[2];
1717 topl_resp_rect(l, &frame);
1718 switch (topl_resp[l]) {
1739 tmp[1] = topl_resp[l];
1743 TextFont(kFontIDGeneva);
1746 MoveTo ((frame.left + frame.right - StringWidth(name)) / 2,
1747 (frame.top + frame.bottom + font.ascent-font.descent-font.leading-1) / 2);
1750 if (l == topl_def_idx)
1752 FrameRoundRect(&frame, 4, 4);
1755 r.right -= SBARWIDTH;
1756 r.bottom -= SBARHEIGHT;
1757 /* Clip to the portrect - scrollbar/growicon *before* adjusting the rect
1758 to be larger than the size of the window (!) */
1760 SectRgn(clip, org_clip, clip);
1761 if (r.right < MIN_RIGHT)
1762 r.right = MIN_RIGHT;
1763 r.top -= aWin->scrollPos * aWin->row_height;
1766 /* If you enable this band of code (and disable the next band), you will get
1767 fewer flickers but a slower performance while drawing the dot line. */
1768 { RgnHandle dotl_rgn = NewRgn();
1771 dotl.right = r.right;
1772 dotl.bottom = r.top + aWin->save_lin * aWin->row_height;
1773 dotl.top = dotl.bottom - 1;
1774 FillRect(&dotl, &qd.gray);
1775 RectRgn(dotl_rgn, &dotl);
1776 DiffRgn(clip, dotl_rgn, clip);
1777 DisposeRgn(dotl_rgn);
1782 if (in_topl_mode()) {
1783 RgnHandle topl_rgn = NewRgn();
1785 topl_r.top += (aWin->y_size - 1) * aWin->row_height;
1786 l = (*top_line)->destRect.right - (*top_line)->destRect.left;
1787 (*top_line)->viewRect = topl_r;
1788 (*top_line)->destRect = topl_r;
1789 if (l != topl_r.right - topl_r.left)
1790 TECalText(top_line);
1791 TEUpdate(&topl_r, top_line);
1792 RectRgn(topl_rgn, &topl_r);
1793 DiffRgn(clip, topl_rgn, clip);
1794 DisposeRgn(topl_rgn);
1800 TextFont (aWin->font_number);
1801 TextSize (aWin->font_size);
1802 HLock (aWin->windowText);
1803 TETextBox (*aWin->windowText, aWin->windowTextLen, &r, teJustLeft);
1804 HUnlock (aWin->windowText);
1806 #if !TARGET_API_MAC_CARBON
1807 r.bottom = r.top + aWin->save_lin * aWin->row_height;
1808 r.top = r.bottom - 1;
1809 FillRect(&r, (void *) &qd.gray);
1813 DisposeRgn(org_clip);
1819 macUpdateMenu (EventRecord *theEvent, WindowPtr theWindow) {
1820 NhWindow *aWin = GetNhWin (theWindow);
1824 GeneralUpdate (theEvent, theWindow);
1825 HLock ((char**)aWin->menuInfo);
1826 HLock ((char**)aWin->menuSelected);
1827 for (i = 0; i < aWin->miSelLen; i++) {
1828 mi = &(*aWin->menuInfo) [(*aWin->menuSelected) [i]];
1830 if (line > aWin->scrollPos && line <= aWin->y_size)
1831 ToggleMenuSelect (aWin, line - aWin->scrollPos);
1833 HUnlock ((char**)aWin->menuInfo);
1834 HUnlock ((char**)aWin->menuSelected);
1840 GeneralUpdate (EventRecord *theEvent, WindowPtr theWindow) {
1842 NhWindow *aWin = GetNhWin (theWindow);
1850 GetWindowBounds(theWindow, kWindowContentRgn, &r);
1851 OffsetRect(&r, -r.left, -r.top);
1853 r2.left = r2.right - SBARWIDTH;
1856 vis = (r2.bottom > r2.top + 50);
1858 draw_growicon_vert_only(theWindow);
1859 DrawControls (theWindow);
1862 if (vis && (h = NewRgn ())) {
1863 RgnHandle tmp = NewRgn ();
1870 DiffRgn (h, tmp, tmp);
1875 if (r.right < MIN_RIGHT)
1876 r.right = MIN_RIGHT;
1877 r.top -= aWin->scrollPos * aWin->row_height;
1878 r.right -= SBARWIDTH;
1879 HLock (aWin->windowText);
1880 TETextBox (*aWin->windowText, aWin->windowTextLen, &r, teJustLeft);
1881 HUnlock (aWin->windowText);
1891 macCursorTerm (EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) {
1892 char *dir_bas, *dir;
1895 NhWindow *nhw = GetNhWin (theWindow);
1896 Rect r = {0, 0, 1, 1};
1899 SetPortWindowPort(theWindow);
1904 Point where = theEvent->where;
1906 GlobalToLocal (&where);
1907 dir_bas = iflags.num_pad ? (char *) ndir : (char *) sdir;
1908 dir = strchr (dir_bas, *click_to_cmd (where.h / nhw->char_width + 1 ,
1909 where.v / nhw->row_height, CLICK_1));
1911 ch = GetCursor (dir ? dir - dir_bas + 513 : 512);
1913 HLock ((Handle) ch);
1915 HUnlock ((Handle) ch);
1918 SetCursor(&qdarrow);
1920 OffsetRect (&r, theEvent->where.h, theEvent->where.v);
1921 RectRgn (mouseRgn, &r);
1927 GeneralCursor (EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) {
1928 #if defined(__SC__) || defined(__MRC__)
1929 # pragma unused(theWindow)
1931 Rect r = {-1, -1, 2, 2};
1933 SetCursor(&qdarrow);
1934 OffsetRect (&r, theEvent->where.h, theEvent->where.v);
1935 RectRgn (mouseRgn, &r);
1940 HandleKey (EventRecord *theEvent) {
1941 WindowPtr theWindow = FrontWindow ();
1943 if (theEvent->modifiers & cmdKey) {
1944 if (theEvent->message & 0xff == '.') {
1945 /* Flush key queue */
1946 keyQueueCount = keyQueueWrite = keyQueueRead = 0;
1947 theEvent->message = '\033';
1951 DoMenuEvt (MenuKey (theEvent->message & 0xff));
1957 int kind = GetWindowKind(theWindow) - WIN_BASE_KIND;
1958 winKeyFuncs [kind] (theEvent, theWindow);
1960 GeneralKey (theEvent, (WindowPtr) 0);
1967 WindowGoAway (EventRecord *theEvent, WindowPtr theWindow) {
1968 NhWindow *aWin = GetNhWin(theWindow);
1970 if (!theEvent || TrackGoAway (theWindow, theEvent->where)) {
1971 if (aWin - theWindows == BASE_WINDOW && !iflags.window_inited) {
1972 AddToKeyQueue ('\033', 1);
1974 HideWindow (theWindow);
1975 if (aWin - theWindows != inSelect)
1976 mac_destroy_nhwindow (aWin - theWindows);
1977 else /* if this IS the inSelect window put a close char */
1978 AddToKeyQueue (CHAR_CR, 1); /* in queue to exit and maintain inSelect */
1985 HandleClick (EventRecord *theEvent) {
1988 WindowPtr theWindow;
1991 Boolean not_inSelect;
1993 InsetRect(GetRegionBounds(GetGrayRgn(), &r), 4, 4);
1995 code = FindWindow (theEvent->where, &theWindow);
1996 aWin = GetNhWin (theWindow);
1997 not_inSelect = (inSelect == WIN_ERR || aWin - theWindows == inSelect);
2002 int kind = GetWindowKind(theWindow) - WIN_BASE_KIND;
2003 winCursorFuncs [kind] (theEvent, theWindow, gMouseRgn);
2004 SelectWindow (theWindow);
2005 SetPortWindowPort(theWindow);
2006 winClickFuncs [kind] (theEvent, theWindow);
2014 SetCursor(&qdarrow);
2015 DragWindow (theWindow, theEvent->where, &r);
2016 SaveWindowPos(theWindow);
2024 SetCursor(&qdarrow);
2025 SetRect (&r, 80, 2 * aWin->row_height + 1, r.right, r.bottom);
2026 if (aWin == theWindows + WIN_MESSAGE)
2027 r.top += SBARHEIGHT;
2028 l = GrowWindow (theWindow, theEvent->where, &r);
2029 SizeWindow (theWindow, l & 0xffff, l >> 16, FALSE);
2030 SaveWindowSize(theWindow);
2031 SetPortWindowPort(theWindow);
2032 GetWindowBounds(theWindow, kWindowContentRgn, &r);
2033 OffsetRect(&r, -r.left, -r.top);
2034 InvalWindowRect(theWindow, &r);
2035 if (aWin->scrollBar) {
2036 DrawScrollbar (aWin);
2044 WindowGoAway(theEvent, theWindow);
2048 DoMenuEvt (MenuSelect (theEvent->where));
2051 #if !TARGET_API_MAC_CARBON
2053 SystemClick(theEvent, theWindow);
2062 HandleUpdate (EventRecord *theEvent) {
2063 WindowPtr theWindow = (WindowPtr) theEvent->message;
2064 NhWindow *aWin = GetNhWin (theWindow);
2068 char existing_update_region = FALSE;
2071 if (theWindow == _mt_window) {
2072 existing_update_region = (get_invalid_region (theWindow, &rect) == noErr);
2074 BeginUpdate (theWindow);
2075 SetPortWindowPort(theWindow);
2076 GetWindowBounds(theWindow, kWindowContentRgn, &r);
2077 OffsetRect(&r, -r.left, -r.top);
2079 winUpdateFuncs [GetWindowKind(theWindow) - WIN_BASE_KIND]
2080 (theEvent, theWindow);
2082 if (theWindow == _mt_window && existing_update_region) {
2083 set_invalid_region (theWindow, &rect);
2086 EndUpdate (theWindow);
2091 DoOsEvt (EventRecord *theEvent) {
2095 if ((theEvent->message & 0xff000000) == 0xfa000000) {
2098 code = FindWindow (theEvent->where, &win);
2099 if (code != inContent) {
2100 Rect r = {-1, -1, 2, 2};
2102 SetCursor(&qdarrow);
2103 OffsetRect (&r, theEvent->where.h, theEvent->where.v);
2104 RectRgn (gMouseRgn, &r);
2106 int kind = GetWindowKind(win) - WIN_BASE_KIND;
2107 if (kind >= 0 && kind <= NHW_TEXT) {
2108 winCursorFuncs [kind] (theEvent, win, gMouseRgn);
2116 HandleEvent (EventRecord *theEvent) {
2117 switch (theEvent->what) {
2120 HandleKey (theEvent);
2123 HandleUpdate (theEvent);
2126 HandleClick (theEvent);
2128 #if !TARGET_API_MAC_CARBON
2130 if ((theEvent->message & 0xffff0000) != 0) {
2131 Point p = {150, 150};
2132 (void) DIBadMount (p, theEvent->message);
2139 case kHighLevelEvent:
2140 AEProcessAppleEvent(theEvent);
2148 mac_get_nh_event(void) {
2149 EventRecord anEvent;
2151 /* KMH -- Don't proceed if the window system isn't set up */
2152 if (!iflags.window_inited)
2155 (void) WaitNextEvent (everyEvent, &anEvent, -1, gMouseRgn);
2156 HandleEvent(&anEvent);
2164 EventRecord anEvent;
2166 /* We want to take care of keys in the buffer as fast as
2173 static char warn = 0;
2175 doDawdle = (in_topl_mode() ? GetCaretTime () : 120L);
2176 /* Since we have time, check memory */
2177 PurgeSpace (&total, &contig);
2178 if (contig < 25000L || total < 50000L) {
2180 pline ("Low Memory!");
2189 (void) WaitNextEvent (everyEvent, &anEvent, doDawdle, gMouseRgn);
2190 HandleEvent (&anEvent);
2191 ch = GetFromKeyQueue ();
2192 } while (!ch && !gClickedToMove);
2194 if (!gClickedToMove)
2200 if (ch == '\r') ch = '\n';
2208 mac_delay_output(void) {
2209 long destTicks = TickCount () + 1;
2211 while (TickCount () < destTicks) {
2212 mac_get_nh_event ();
2219 mac_cliparound (int x, int y) {
2220 #if defined(__SC__) || defined(__MRC__)
2221 # pragma unused(x,y)
2228 mac_exit_nhwindows (const char *s) {
2230 tty_exit_nhwindows (s);
2231 mac_destroy_nhwindow (WIN_MESSAGE);
2232 mac_destroy_nhwindow (WIN_INVEN);
2237 * Don't forget to decrease in_putstr before returning...
2240 mac_putstr (winid win, int attr, const char *str) {
2242 NhWindow *aWin = &theWindows [win];
2243 static char in_putstr = 0;
2244 short newWidth, maxWidth;
2246 char *src, *sline, *dst, ch;
2248 if (win < 0 || win >= NUM_MACWINDOWS || !aWin->its_window) {
2249 error ("putstr: Invalid win %d (Max %d).", win, NUM_MACWINDOWS, attr);
2253 if (aWin->its_window == _mt_window) {
2254 tty_putstr(win, attr, str);
2262 slen = strlen (str);
2264 SetPortWindowPort(aWin->its_window);
2265 GetWindowBounds(aWin->its_window, kWindowContentRgn, &r);
2266 OffsetRect(&r, -r.left, -r.top);
2267 if (win == WIN_MESSAGE) {
2268 r.right -= SBARWIDTH;
2269 r.bottom -= SBARHEIGHT;
2270 if (flags.page_wait &&
2271 aWin->last_more_lin <= aWin->y_size - (r.bottom - r.top) / aWin->row_height) {
2272 aWin->last_more_lin = aWin->y_size;
2273 mac_display_nhwindow(win, TRUE);
2278 * A "default" text window - uses TETextBox
2279 * We just add the text, without attributes for now
2281 len = GetHandleSize (aWin->windowText);
2282 while (aWin->windowTextLen + slen + 1 > len) {
2283 len = (len > 2048) ? (len + 2048) : (len * 2);
2284 SetHandleSize (aWin->windowText, len);
2286 error ("putstr: SetHandleSize");
2287 aWin->windowTextLen = 0L;
2294 len = aWin->windowTextLen;
2295 dst = *(aWin->windowText) + len;
2296 sline = src = (char *)str;
2297 maxWidth = newWidth = 0;
2298 for (ch = *src; ch; ch = *src) {
2302 if (ch == CHAR_CR) {
2306 newWidth = TextWidth (sline, 0, src - sline);
2307 if (newWidth > maxWidth) {
2308 maxWidth = newWidth;
2310 sline = src+1; /* keep track of where new line begins */
2317 newWidth = TextWidth (sline, 0, src - sline);
2318 if (newWidth > maxWidth) {
2319 maxWidth = newWidth;
2322 aWin->windowTextLen += slen;
2324 if (ch != CHAR_CR) {
2325 (*(aWin->windowText)) [len + slen] = CHAR_CR;
2326 aWin->windowTextLen ++;
2332 if (win == WIN_MESSAGE) {
2333 short min = aWin->y_size - (r.bottom - r.top) / aWin->row_height;
2334 if (aWin->scrollPos < min) {
2335 aWin->scrollPos = min;
2336 SetControlMaximum (aWin->scrollBar, aWin->y_size);
2337 SetControlValue(aWin->scrollBar, min);
2339 InvalWindowRect(aWin->its_window, &r);
2341 else /* Message has a fixed width, other windows base on content */
2342 if (maxWidth > aWin->x_size)
2343 aWin->x_size = maxWidth;
2349 mac_curs (winid win, int x, int y) {
2350 NhWindow *aWin = &theWindows [win];
2352 if (aWin->its_window == _mt_window) {
2353 tty_curs(win, x, y);
2357 SetPortWindowPort(aWin->its_window);
2358 MoveTo (x * aWin->char_width, (y * aWin->row_height) + aWin->ascent_height);
2365 mac_nh_poskey (int *a, int *b, int *c) {
2366 int ch = mac_nhgetch();
2375 mac_start_menu (winid win) {
2376 HideWindow (theWindows [win].its_window);
2377 mac_clear_nhwindow (win);
2382 mac_add_menu (winid win, int glyph, const anything *any, CHAR_P menuChar, CHAR_P groupAcc, int attr, const char *inStr, int preselected) {
2383 #if defined(__SC__) || defined(__MRC__)
2384 # pragma unused(glyph)
2386 NhWindow *aWin = &theWindows [win];
2388 char locStr[4+BUFSZ];
2389 MacMHMenuItem *item;
2393 if (any->a_void != 0) {
2395 #define kMenuSizeBump 26
2396 if (!aWin->miSize) {
2397 aWin->menuInfo = (MacMHMenuItem **)NewHandle(sizeof(MacMHMenuItem) * kMenuSizeBump);
2398 if (!aWin->menuInfo) {
2399 error("Can't alloc menu handle");
2402 aWin->menuSelected = (short **)NewHandle(sizeof(short) * kMenuSizeBump);
2403 if (!aWin->menuSelected) {
2404 error("Can't alloc menu select handle");
2407 aWin->miSize = kMenuSizeBump;
2410 if (aWin->miLen >= aWin->miSize) {
2411 SetHandleSize((Handle)aWin->menuInfo, sizeof(MacMHMenuItem) * (aWin->miLen+kMenuSizeBump));
2413 error("Can't resize menu handle");
2416 SetHandleSize((Handle)aWin->menuSelected, sizeof(short) * (aWin->miLen+kMenuSizeBump));
2418 error("Can't resize menu select handle");
2421 aWin->miSize += kMenuSizeBump;
2424 if (menuChar == 0) {
2425 if (('a' <= aWin->menuChar && aWin->menuChar <= 'z') ||
2426 ('A' <= aWin->menuChar && aWin->menuChar <= 'Z')) {
2427 menuChar = aWin->menuChar++;
2428 if (menuChar == 'z')
2429 aWin->menuChar = 'A';
2433 Sprintf(locStr, "%c - %s", (menuChar ? menuChar : ' '), inStr);
2435 HLock ((char**)aWin->menuInfo);
2436 HLock ((char**)aWin->menuSelected);
2437 (*aWin->menuSelected)[aWin->miLen] = preselected;
2438 item = &(*aWin->menuInfo)[aWin->miLen];
2441 item->accelerator = menuChar;
2442 item->groupAcc = groupAcc;
2443 item->line = aWin->y_size;
2444 HUnlock ((char**)aWin->menuInfo);
2445 HUnlock ((char**)aWin->menuSelected);
2449 putstr (win, attr, str);
2454 * End a menu in this window, window must a type NHW_MENU.
2455 * str is a list of cancel characters (values that may be input)
2456 * morestr is a prompt to display, rather than the default.
2457 * str and morestr might be ignored by some ports.
2460 mac_end_menu (winid win, const char *morestr) {
2462 NhWindow *aWin = &theWindows [win];
2467 SetWTitle (aWin->its_window, buf);
2472 mac_select_menu (winid win, int how, menu_item **selected_list) {
2474 NhWindow *aWin = &theWindows [win];
2475 WindowPtr theWin = aWin->its_window;
2479 mac_display_nhwindow (win, FALSE);
2481 aWin->how = (short) how;
2483 c = map_menu_cmd (mac_nhgetch());
2484 if (c == CHAR_ESC) {
2485 /* deselect everything */
2488 } else if (ClosingWindowChar(c)) {
2495 HideWindow (theWin);
2497 if (aWin->miSelLen) {
2500 *selected_list = mp = (menu_item *) alloc(aWin->miSelLen * sizeof(menu_item));
2501 HLock ((char**)aWin->menuInfo);
2502 HLock ((char**)aWin->menuSelected);
2503 for (c = 0; c < aWin->miSelLen; c++) {
2504 mi = &(*aWin->menuInfo)[(*aWin->menuSelected) [c]];
2509 HUnlock ((char**)aWin->menuInfo);
2510 HUnlock ((char**)aWin->menuSelected);
2516 return aWin->miSelLen;
2522 mac_display_file (name, complain)
2523 const char *name; /* not ANSI prototype because of boolean parameter */
2528 dlb *fp = dlb_fopen(name, "r");
2531 long l = dlb_fseek(fp, 0, SEEK_END);
2532 (void) dlb_fseek(fp, 0, 0L);
2535 l = dlb_fread(buf, 1, l, fp);
2538 win = create_nhwindow(NHW_TEXT);
2539 if (WIN_ERR == win) {
2540 if (complain) error ("Cannot make window.");
2542 putstr(win, 0, buf);
2543 display_nhwindow(win, FALSE);
2549 } else if (complain)
2550 error("Cannot open %s.", name);
2556 display_file (PORT_HELP, TRUE);
2561 mac_unimplemented (void) {
2566 mac_suspend_nhwindows (const char *foo) {
2567 #if defined(__SC__) || defined(__MRC__)
2568 # pragma unused(foo)
2570 /* Can't really do that :-) */
2575 try_key_queue (char *bufp) {
2576 if (keyQueueCount) {
2578 for (ch = GetFromKeyQueue(); ; ch = GetFromKeyQueue()) {
2579 if (ch == CHAR_LF || ch == CHAR_CR)
2590 /* Interface definition, for windows.c */
2591 struct window_procs mac_procs = {
2593 WC_COLOR | WC_HILITE_PET |
2594 WC_FONT_MAP | WC_FONT_MENU | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_TEXT |
2595 WC_FONTSIZ_MAP | WC_FONTSIZ_MENU | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_TEXT,
2598 mac_unimplemented, /* see macmenu.c:mac_askname() for player selection */
2602 mac_suspend_nhwindows,
2604 mac_create_nhwindow,
2606 mac_display_nhwindow,
2607 mac_destroy_nhwindow,
2639 tty_change_background,
2641 tty_get_color_string,
2643 /* other defs that really should go away (they're tty specific) */
2644 0, // mac_start_screen,
2645 0, // mac_end_screen,
2647 genl_preference_update,