⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 macterm.c

📁 远程登陆工具软件源码 用于远程登陆unix
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: macterm.c,v 1.76 2004/06/20 17:07:37 jacob Exp $ */
/*
 * Copyright (c) 1999 Simon Tatham
 * Copyright (c) 1999, 2002 Ben Harris
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * macterm.c -- Macintosh terminal front-end
 */

#include <MacTypes.h>
#include <Controls.h>
#include <ControlDefinitions.h>
#include <FixMath.h>
#include <Fonts.h>
#include <Gestalt.h>
#include <LowMem.h>
#include <MacMemory.h>
#include <MacWindows.h>
#include <MixedMode.h>
#include <Palettes.h>
#include <Quickdraw.h>
#include <QuickdrawText.h>
#include <Resources.h>
#include <Scrap.h>
#include <Script.h>
#include <Sound.h>
#include <TextCommon.h>
#include <ToolUtils.h>
#include <UnicodeConverter.h>

#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "macresid.h"
#include "putty.h"
#include "charset.h"
#include "mac.h"
#include "terminal.h"

#define NCOLOURS (lenof(((Config *)0)->colours))

#define DEFAULT_FG	16
#define DEFAULT_FG_BOLD	17
#define DEFAULT_BG	18
#define DEFAULT_BG_BOLD	19
#define CURSOR_FG	20
#define CURSOR_BG	21

#define PTOCC(x) ((x) < 0 ? -(-(x - s->font_width - 1) / s->font_width) : \
			    (x) / s->font_width)
#define PTOCR(y) ((y) < 0 ? -(-(y - s->font_height - 1) / s->font_height) : \
			    (y) / s->font_height)

static void mac_initfont(Session *);
static pascal OSStatus uni_to_font_fallback(UniChar *, ByteCount, ByteCount *,
					    TextPtr, ByteCount, ByteCount *,
					    LogicalAddress,
					    ConstUnicodeMappingPtr);
static void mac_initpalette(Session *);
static void mac_adjustwinbg(Session *);
static void mac_adjustsize(Session *, int, int);
static void mac_drawgrowicon(Session *s);
static pascal void mac_growtermdraghook(void);
static pascal void mac_scrolltracker(ControlHandle, short);
static pascal void do_text_for_device(short, short, GDHandle, long);
static void text_click(Session *, EventRecord *);
static void mac_activateterm(WindowPtr, EventRecord *);
static void mac_adjusttermcursor(WindowPtr, Point, RgnHandle);
static void mac_adjusttermmenus(WindowPtr);
static void mac_updateterm(WindowPtr);
static void mac_clickterm(WindowPtr, EventRecord *);
static void mac_growterm(WindowPtr, EventRecord *);
static void mac_keyterm(WindowPtr, EventRecord *);
static void mac_menuterm(WindowPtr, short, short);
static void mac_closeterm(WindowPtr);

void pre_paint(Session *s);
void post_paint(Session *s);

void mac_startsession(Session *s)
{
    const char *errmsg;
    int i;
    WinInfo *wi;

    init_ucs(s);

    /*
     * Select protocol. This is farmed out into a table in a
     * separate file to enable an ssh-free variant.
     */
    s->back = NULL;
    for (i = 0; backends[i].backend != NULL; i++)
	if (backends[i].protocol == s->cfg.protocol) {
	    s->back = backends[i].backend;
	    break;
	}
    if (s->back == NULL)
	fatalbox("Unsupported protocol number found");

    /* XXX: Own storage management? */
    if (HAVE_COLOR_QD())
	s->window = GetNewCWindow(wTerminal, NULL, (WindowPtr)-1);
    else
	s->window = GetNewWindow(wTerminal, NULL, (WindowPtr)-1);
    wi = snew(WinInfo);
    memset(wi, 0, sizeof(*wi));
    wi->s = s;
    wi->wtype = wTerminal;
    wi->activate = &mac_activateterm;
    wi->adjustcursor = &mac_adjusttermcursor;
    wi->adjustmenus = &mac_adjusttermmenus;
    wi->update = &mac_updateterm;
    wi->click = &mac_clickterm;
    wi->grow = &mac_growterm;
    wi->key = &mac_keyterm;
    wi->menu = &mac_menuterm;
    wi->close = &mac_closeterm;
    SetWRefCon(s->window, (long)wi);
    s->scrollbar = GetNewControl(cVScroll, s->window);
    s->term = term_init(&s->cfg, &s->ucsdata, s);

    mac_initfont(s);
    mac_initpalette(s);
    if (HAVE_COLOR_QD()) {
	/* Set to FALSE to not get palette updates in the background. */
	SetPalette(s->window, s->palette, TRUE); 
	ActivatePalette(s->window);
    }

    s->logctx = log_init(s->term, &s->cfg);
    term_provide_logctx(s->term, s->logctx);

    errmsg = s->back->init(s, &s->backhandle, &s->cfg, s->cfg.host,
			   s->cfg.port, &s->realhost, s->cfg.tcp_nodelay,
			   s->cfg.tcp_keepalives);
    if (errmsg != NULL)
	fatalbox("%s", errmsg);
    s->back->provide_logctx(s->backhandle, s->logctx);
    set_title(s, s->realhost);

    term_provide_resize_fn(s->term, s->back->size, s->backhandle);

    mac_adjustsize(s, s->cfg.height, s->cfg.width);
    term_size(s->term, s->cfg.height, s->cfg.width, s->cfg.savelines);

    s->ldisc = ldisc_create(&s->cfg, s->term, s->back, s->backhandle, s);
    ldisc_send(s->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */

    ShowWindow(s->window);
    s->next = sesslist;
    s->prev = &sesslist;
    if (s->next != NULL)
	s->next->prev = &s->next;
    sesslist = s;
}

/*
 * Try to work out a horizontal scaling factor for the current font
 * that will give a chracter width of wantwidth.  Return it in numer
 * and denom (suitable for passing to StdText()).
 */
static void mac_workoutfontscale(Session *s, int wantwidth,
				 Point *numerp, Point *denomp)
{
    Point numer, denom, tmpnumer, tmpdenom;
    int gotwidth, i;
    const char text = 'W';
    FontInfo fi;
#if TARGET_API_MAC_CARBON
    CQDProcsPtr gp = GetPortGrafProcs(GetWindowPort(s->window));
#else
    QDProcsPtr gp = s->window->grafProcs;
#endif

    numer.v = denom.v = 1; /* always */
    numer.h = denom.h = 1;
    for (i = 0; i < 3; i++) {
	tmpnumer = numer;
	tmpdenom = denom;
	if (gp != NULL)
	    gotwidth = InvokeQDTxMeasUPP(1, &text, &tmpnumer, &tmpdenom, &fi,
					 gp->txMeasProc);
	else
	    gotwidth = StdTxMeas(1, &text, &tmpnumer, &tmpdenom, &fi);
	/* The result of StdTxMeas must be scaled by the factors it returns. */
	gotwidth = FixRound(FixMul(gotwidth << 16,
				   FixRatio(tmpnumer.h, tmpdenom.h)));
	if (gotwidth == wantwidth)
	    break;
	numer.h *= wantwidth;
	denom.h *= gotwidth;
    }
    *numerp = numer;
    *denomp = denom;
}

static UnicodeToTextFallbackUPP uni_to_font_fallback_upp;

static void mac_initfont(Session *s)
{
    FontInfo fi;
    TextEncoding enc;
    OptionBits fbflags;

    SetPort((GrafPtr)GetWindowPort(s->window));
    GetFNum(s->cfg.font.name, &s->fontnum);
    TextFont(s->fontnum);
    TextFace(s->cfg.font.face);
    TextSize(s->cfg.font.size);
    GetFontInfo(&fi);
    s->font_width = CharWidth('W'); /* Well, it's what NCSA uses. */
    s->font_ascent = fi.ascent;
    s->font_leading = fi.leading;
    s->font_height = s->font_ascent + fi.descent + s->font_leading;
    mac_workoutfontscale(s, s->font_width,
			 &s->font_stdnumer, &s->font_stddenom);
    mac_workoutfontscale(s, s->font_width * 2,
			 &s->font_widenumer, &s->font_widedenom);
    TextSize(s->cfg.font.size * 2);
    mac_workoutfontscale(s, s->font_width * 2,
			 &s->font_bignumer, &s->font_bigdenom);
    TextSize(s->cfg.font.size);
    if (!s->cfg.bold_colour) {
	TextFace(bold);
	s->font_boldadjust = s->font_width - CharWidth('W');
    } else
	s->font_boldadjust = 0;

    if (s->uni_to_font != NULL)
	DisposeUnicodeToTextInfo(&s->uni_to_font);
    if (mac_gestalts.encvvers != 0 &&
	UpgradeScriptInfoToTextEncoding(kTextScriptDontCare,
					kTextLanguageDontCare,
					kTextRegionDontCare, s->cfg.font.name,
					&enc) == noErr &&
	CreateUnicodeToTextInfoByEncoding(enc, &s->uni_to_font) == noErr) {
	if (uni_to_font_fallback_upp == NULL)
	    uni_to_font_fallback_upp =
		NewUnicodeToTextFallbackUPP(&uni_to_font_fallback);
	fbflags = kUnicodeFallbackCustomOnly;
	if (mac_gestalts.uncvattr & kTECAddFallbackInterruptMask)
	    fbflags |= kUnicodeFallbackInterruptSafeMask;
	if (SetFallbackUnicodeToText(s->uni_to_font,
	    uni_to_font_fallback_upp, fbflags, NULL) != noErr) {
	    DisposeUnicodeToTextInfo(&s->uni_to_font);
	    goto no_encv;
	}
    } else {
	char cfontname[256];

      no_encv:
	s->uni_to_font = NULL;
	p2cstrcpy(cfontname, s->cfg.font.name);
	s->font_charset =
	    charset_from_macenc(FontToScript(s->fontnum),
				GetScriptManagerVariable(smRegionCode),
				mac_gestalts.sysvers, cfontname);
    }

    mac_adjustsize(s, s->term->rows, s->term->cols);
}

static pascal OSStatus uni_to_font_fallback(UniChar *ucp,
    ByteCount ilen, ByteCount *iusedp, TextPtr obuf, ByteCount olen,
    ByteCount *ousedp, LogicalAddress cookie, ConstUnicodeMappingPtr mapping)
{

    if (olen < 1)
	return kTECOutputBufferFullStatus;
    /*
     * What I'd _like_ to do here is to somehow generate the
     * missing-character glyph that every font is required to have.
     * Unfortunately (and somewhat surprisingly), I can't find any way
     * to actually ask for it explicitly.  Bah.
     */
    *obuf = '.';
    *iusedp = ilen;
    *ousedp = 1;
    return noErr;
}

/*
 * Called every time round the event loop.
 */
void mac_pollterm(void)
{
    Session *s;

    for (s = sesslist; s != NULL; s = s->next) {
	term_out(s->term);
	term_update(s->term);
    }
}

/*
 * To be called whenever the window size changes.
 * rows and cols should be desired values.
 * It's assumed the terminal emulator will be informed, and will set rows
 * and cols for us.
 */
static void mac_adjustsize(Session *s, int newrows, int newcols) {
    int winwidth, winheight;

    winwidth = newcols * s->font_width + 15;
    winheight = newrows * s->font_height;
    SizeWindow(s->window, winwidth, winheight, true);
    HideControl(s->scrollbar);
    MoveControl(s->scrollbar, winwidth - 15, -1);
    SizeControl(s->scrollbar, 16, winheight - 13);
    ShowControl(s->scrollbar);
    mac_drawgrowicon(s);
}

static void mac_initpalette(Session *s)
{

    if (!HAVE_COLOR_QD())
	return;
    /*
     * Most colours should be inhibited on 2bpp displays.
     * Palette manager documentation suggests inhibiting all tolerant colours
     * on greyscale displays.
     */
#define PM_NORMAL 	( pmTolerant | pmInhibitC2 |			\
			  pmInhibitG2 | pmInhibitG4 | pmInhibitG8 )
#define PM_TOLERANCE	0x2000
    s->palette = NewPalette(22, NULL, PM_NORMAL, PM_TOLERANCE);
    if (s->palette == NULL)
	fatalbox("Unable to create palette");
    /* In 2bpp, these are the colours we want most. */
    SetEntryUsage(s->palette, DEFAULT_BG,
		  PM_NORMAL &~ pmInhibitC2, PM_TOLERANCE);
    SetEntryUsage(s->palette, DEFAULT_FG,
		  PM_NORMAL &~ pmInhibitC2, PM_TOLERANCE);
    SetEntryUsage(s->palette, DEFAULT_FG_BOLD,
		  PM_NORMAL &~ pmInhibitC2, PM_TOLERANCE);
    SetEntryUsage(s->palette, CURSOR_BG,
		  PM_NORMAL &~ pmInhibitC2, PM_TOLERANCE);
    palette_reset(s);
}

/*
 * Set the background colour of the window correctly.  Should be
 * called whenever the default background changes.
 */
static void mac_adjustwinbg(Session *s)
{

    if (!HAVE_COLOR_QD())
	return;
#if !TARGET_CPU_68K
    if (mac_gestalts.windattr & gestaltWindowMgrPresent)
	SetWindowContentColor(s->window,
			      &(*s->palette)->pmInfo[DEFAULT_BG].ciRGB);
    else
#endif
    {
#if !TARGET_API_MAC_CARBON
	if (s->wctab == NULL)
	    s->wctab = (WCTabHandle)NewHandle(sizeof(**s->wctab));
	if (s->wctab == NULL)
	    return; /* do without */
	(*s->wctab)->wCSeed = 0;
	(*s->wctab)->wCReserved = 0;
	(*s->wctab)->ctSize = 0;
	(*s->wctab)->ctTable[0].value = wContentColor;
	(*s->wctab)->ctTable[0].rgb = (*s->palette)->pmInfo[DEFAULT_BG].ciRGB;
	SetWinColor(s->window, s->wctab);
#endif
    }
}

/*
 * Set the cursor shape correctly
 */
static void mac_adjusttermcursor(WindowPtr window, Point mouse,
				 RgnHandle cursrgn)
{
    Session *s;
    ControlHandle control;
    short part;
    int x, y;
#if TARGET_API_MAC_CARBON
    Cursor arrow;
    Rect rect;
    RgnHandle visrgn;
#endif

    SetPort((GrafPtr)GetWindowPort(window));
    s = mac_windowsession(window);
    GlobalToLocal(&mouse);
    part = FindControl(mouse, window, &control);
    if (control == s->scrollbar) {
#if TARGET_API_MAC_CARBON
	SetCursor(GetQDGlobalsArrow(&arrow));
	RectRgn(cursrgn, GetControlBounds(s->scrollbar, &rect));
#else
	SetCursor(&qd.arrow);
	RectRgn(cursrgn, &(*s->scrollbar)->contrlRect);
#endif
    } else {
	x = mouse.h / s->font_width;
	y = mouse.v / s->font_height;
	if (s->raw_mouse) {
#if TARGET_API_MAC_CARBON
	    SetCursor(GetQDGlobalsArrow(&arrow));
#else
	    SetCursor(&qd.arrow);
#endif
	} else
	    SetCursor(*GetCursor(iBeamCursor));
	/* Ask for shape changes if we leave this character cell. */
	SetRectRgn(cursrgn, x * s->font_width, y * s->font_height,
		   (x + 1) * s->font_width, (y + 1) * s->font_height);
    }
#if TARGET_API_MAC_CARBON
    visrgn = NewRgn();
    GetPortVisibleRegion(GetWindowPort(window), visrgn);
    SectRgn(cursrgn, visrgn, cursrgn);
    DisposeRgn(visrgn);
#else	
    SectRgn(cursrgn, window->visRgn, cursrgn);
#endif
}

/*
 * Enable/disable menu items based on the active terminal window.
 */
#if TARGET_API_MAC_CARBON
#define DisableItem DisableMenuItem
#define EnableItem EnableMenuItem
#endif
static void mac_adjusttermmenus(WindowPtr window)
{
    Session *s;
    MenuHandle menu;
#if !TARGET_API_MAC_CARBON
    long offset;
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -