Compare commits

...

38 Commits
r2 ... master

Author SHA1 Message Date
Kelvin Sherlock
43cb3c9e4f esc [0J was dropping through to esc[1J 2022-11-25 14:49:22 -05:00
ksherlock
6cb2b91ac0
fix answer back string
testing with an actual vt100, answer back is a string defined in the setup B screen. It is unrelated to the device attributes.
2021-04-22 23:10:55 -04:00
Kelvin Sherlock
8a5f5a9e61 bump submodule 2021-03-27 23:55:54 -04:00
Kelvin Sherlock
b1340d2a56 mousetext flag was blocking inverse flag. 2021-03-27 23:53:52 -04:00
ksherlock
5a971ac08c
Update xcodebuild.yml 2020-11-14 20:42:15 -05:00
ksherlock
254dfd548e
Update xcodebuild.yml 2020-11-14 20:14:30 -05:00
ksherlock
bd6d13e51b
Create xcodebuild.yml 2020-11-14 17:38:47 -05:00
Kelvin Sherlock
54335e2e3b xcode upgrade, adjust signing settings. 2020-11-14 17:17:29 -05:00
Kelvin Sherlock
98dc438fa5 vt100: up/down/left/right were always limited to 1 position. fixed. 2019-01-08 23:28:49 -05:00
Kelvin Sherlock
ceb1349199 Project update. 2018-12-25 13:56:10 -05:00
Kelvin Sherlock
22266914ed Add Apple III console support. Not usable via termcap since cursor positioning uses 0x00 which is converted by terminfo to 0x80 which has a very different meaning (last column/row vs first column/row). 2018-12-25 13:55:36 -05:00
Kelvin Sherlock
542dddd335 OS X Mojave hardening. 2018-11-24 14:29:16 -05:00
Kelvin Sherlock
6b28a1e170 version bump. 2018-11-24 13:39:42 -05:00
Kelvin Sherlock
fd50370e8d project update. 2018-11-24 13:27:03 -05:00
Kelvin Sherlock
92d89dd630 missing release. 2018-11-24 13:26:55 -05:00
Kelvin Sherlock
6f409db93e vt100 wip. 2018-11-24 13:26:47 -05:00
Kelvin Sherlock
30df8aef9e convert characters to 8-bit greyscale to work around OS X Mojave CreateImageMask() bug. 2018-11-24 12:28:56 -05:00
Kelvin Sherlock
99f5d60be8 rewrite VT05 / VT50 / VT50H with ragel. 2018-03-03 10:23:57 -05:00
Kelvin Sherlock
020b095542 reset / hard reset menus. 2018-02-28 21:06:06 -05:00
Kelvin Sherlock
bcf03e124b add 40-column Apple console. 2018-02-28 10:23:58 -05:00
Kelvin Sherlock
0bc20c6fa8 char gen. 2018-02-28 10:23:44 -05:00
Kelvin Sherlock
e7ebb7b573 emulators can specify their character generator. 2018-02-28 10:22:55 -05:00
Kelvin Sherlock
b766854f80 multiple character generators. 2018-02-28 10:22:20 -05:00
Kelvin Sherlock
5b8c8fec17 version bump 2018-02-16 22:22:29 -05:00
Kelvin Sherlock
92e1805694 move colors, etc, to a defaults file... 2018-02-16 17:56:21 -05:00
Kelvin Sherlock
24248e768b add icons. 2018-02-16 17:54:36 -05:00
Kelvin Sherlock
01c89f4715 retina character generator. 2018-02-16 17:52:41 -05:00
Kelvin Sherlock
bf7e733e8b emulator view - init fd to -1 2018-02-14 11:14:51 -05:00
Kelvin Sherlock
49b165a56d add close button to config window. 2018-02-14 11:14:36 -05:00
Kelvin Sherlock
dc097da462 version bump 2018-02-09 22:58:49 -05:00
Kelvin Sherlock
41c311fb8a Squashed commit of the following:
commit b9723cf13690c3a6ecefeee81b1d95a23bde0422
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Feb 9 22:41:59 2018 -0500

    remove most gui config stuff from new window.

commit c690c5ebd99d6268f605094f429114a39ab3c180
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Thu Feb 8 11:48:29 2018 -0500

    crosshatch cursor, push/pop cursor state when no longer key window.

commit ebaa0e535ee52a85a514efbaa872f891f7e817f1
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Thu Feb 8 11:47:20 2018 -0500

    child monitor - removeAll

commit e591630339f3cd22ca461f2006f4c360fa43d026
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Thu Feb 8 11:46:19 2018 -0500

    add config popup for the term window.
2018-02-09 22:47:20 -05:00
Kelvin Sherlock
4507998f1d version bump 2018-01-31 22:54:46 -05:00
Kelvin Sherlock
9fcf9f333f fix (?) some bugs with IIe/gsos high-bit characters. 2018-01-31 22:37:52 -05:00
Kelvin Sherlock
6a117c7b8a include the a2-terminfo database 2018-01-31 22:37:23 -05:00
Kelvin Sherlock
5bd035e33e add terminfo submodule 2018-01-31 22:02:21 -05:00
Kelvin Sherlock
66040a8366 add ChildMonitor sources to xcode project. 2018-01-31 21:19:31 -05:00
Kelvin Sherlock
b63b60826d set TERMINFO_DIRS to bundle/Resources/terminfo. 2018-01-31 21:19:05 -05:00
Kelvin Sherlock
e0bc21d663 move all the child/fd/kevent monitoring to a dedicated thread / class. 2018-01-31 21:17:31 -05:00
75 changed files with 3964 additions and 1124 deletions

21
.github/workflows/xcodebuild.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: xcodebuild
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: brew
run: brew install ragel
- name: xcodebuild
run: xcodebuild -target TwoTerm | xcpretty

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "a2-terminfo"]
path = a2-terminfo
url = https://github.com/ksherlock/a2-terminfo

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13529"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@ -63,8 +63,8 @@
</items>
</menu>
</menuItem>
<menuItem title="File" id="83">
<menu key="submenu" title="File" id="81">
<menuItem title="Shell" id="83">
<menu key="submenu" title="Shell" id="81">
<items>
<menuItem title="New" keyEquivalent="n" id="82">
<connections>
@ -112,6 +112,19 @@
<action selector="revertDocumentToSaved:" target="-1" id="364"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="1Bf-fE-VAI"/>
<menuItem title="Reset" keyEquivalent="r" id="h3z-Y4-dyj">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="resetTerminal:" target="-1" id="Afh-EL-aOa"/>
</connections>
</menuItem>
<menuItem title="Hard Reset" keyEquivalent="r" id="CX0-e3-Dg4">
<modifierMask key="keyEquivalentModifierMask" control="YES" option="YES" command="YES"/>
<connections>
<action selector="hardResetTerminal:" target="-1" id="bVS-nP-oag"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="74">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
@ -342,268 +355,6 @@
</items>
</menu>
</menuItem>
<menuItem title="Format" id="375">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="376">
<items>
<menuItem title="Font" id="377">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="388">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="389">
<connections>
<action selector="orderFrontFontPanel:" target="420" id="424"/>
</connections>
</menuItem>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="390">
<connections>
<action selector="addFontTrait:" target="420" id="421"/>
</connections>
</menuItem>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="391">
<connections>
<action selector="addFontTrait:" target="420" id="422"/>
</connections>
</menuItem>
<menuItem title="Underline" keyEquivalent="u" id="392">
<connections>
<action selector="underline:" target="-1" id="432"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="393"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="394">
<connections>
<action selector="modifyFont:" target="420" id="425"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="395">
<connections>
<action selector="modifyFont:" target="420" id="423"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="396"/>
<menuItem title="Kern" id="397">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="415">
<items>
<menuItem title="Use Default" id="416">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="-1" id="438"/>
</connections>
</menuItem>
<menuItem title="Use None" id="417">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="-1" id="441"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="418">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="-1" id="431"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="419">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="-1" id="435"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligature" id="398">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligature" id="411">
<items>
<menuItem title="Use Default" id="412">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="-1" id="439"/>
</connections>
</menuItem>
<menuItem title="Use None" id="413">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="-1" id="440"/>
</connections>
</menuItem>
<menuItem title="Use All" id="414">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="-1" id="434"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="399">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="405">
<items>
<menuItem title="Use Default" id="406">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="-1" id="437"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="407">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="-1" id="430"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="408">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="-1" id="429"/>
</connections>
</menuItem>
<menuItem title="Raise" id="409">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="-1" id="426"/>
</connections>
</menuItem>
<menuItem title="Lower" id="410">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="-1" id="427"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="400"/>
<menuItem title="Show Colors" keyEquivalent="C" id="401">
<connections>
<action selector="orderFrontColorPanel:" target="-1" id="433"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="402"/>
<menuItem title="Copy Style" keyEquivalent="c" id="403">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="-1" id="428"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="404">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="-1" id="436"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="496">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="497">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="498">
<connections>
<action selector="alignLeft:" target="-1" id="524"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="499">
<connections>
<action selector="alignCenter:" target="-1" id="518"/>
</connections>
</menuItem>
<menuItem title="Justify" id="500">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="-1" id="523"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="501">
<connections>
<action selector="alignRight:" target="-1" id="521"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="502"/>
<menuItem title="Writing Direction" id="503">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="508">
<items>
<menuItem title="Paragraph" enabled="NO" id="509">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="510">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="525"/>
</connections>
</menuItem>
<menuItem id="511">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="526"/>
</connections>
</menuItem>
<menuItem id="512">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="527"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="513"/>
<menuItem title="Selection" enabled="NO" id="514">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="515">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="-1" id="528"/>
</connections>
</menuItem>
<menuItem id="516">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="529"/>
</connections>
</menuItem>
<menuItem id="517">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="530"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="504"/>
<menuItem title="Show Ruler" id="505">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="-1" id="520"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="506">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="-1" id="522"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="507">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="-1" id="519"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="295">
<menu key="submenu" title="View" id="296">
<items>
@ -618,6 +369,11 @@
<action selector="runToolbarCustomizationPalette:" target="-1" id="365"/>
</connections>
</menuItem>
<menuItem title="Configure" keyEquivalent="i" id="6in-Fp-JDh">
<connections>
<action selector="configure:" target="-1" id="5yK-Bh-svP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>

163
Base.lproj/NewTerminal.xib Normal file
View File

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
<capability name="box content view" minToolsVersion="7.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NewTerminalWindowController">
<connections>
<outlet property="backgroundColorControl" destination="53" id="65"/>
<outlet property="colorSchemeButton" destination="68" id="92"/>
<outlet property="foregroundColorControl" destination="49" id="64"/>
<outlet property="terminalTypeButton" destination="55" id="67"/>
<outlet property="window" destination="1" id="38"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="New Terminal" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="1">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" texturedBackground="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="232" width="400" height="218"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
<view key="contentView" wantsLayer="YES" misplaced="YES" id="2">
<rect key="frame" x="0.0" y="0.0" width="400" height="218"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="9">
<rect key="frame" x="17" y="178" width="99" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Terminal Type:" id="10">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" misplaced="YES" id="17">
<rect key="frame" x="262" y="18" width="118" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" title="Connect" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="18">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="connectButton:" target="-2" id="41"/>
</connections>
</button>
<popUpButton verticalHuggingPriority="750" id="55">
<rect key="frame" x="121" y="173" width="259" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="roundTextured" title="Item 1" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" selectedItem="58" id="56">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" title="OtherViews" id="57">
<items>
<menuItem title="Item 1" state="on" id="58"/>
<menuItem title="Item 2" id="59"/>
<menuItem title="Item 3" id="60"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<box autoresizesSubviews="NO" borderType="line" title="Colors" id="76">
<rect key="frame" x="17" y="46" width="366" height="124"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<view key="contentView" id="xsD-uS-uc3">
<rect key="frame" x="1" y="1" width="364" height="108"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="50">
<rect key="frame" x="15" y="48" width="83" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Foreground:" id="51">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="90">
<rect key="frame" x="15" y="79" width="83" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Scheme:" id="91">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="52">
<rect key="frame" x="15" y="17" width="83" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Background:" id="54">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<colorWell id="49">
<rect key="frame" x="103" y="45" width="44" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="color" red="0.0" green="1" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<action selector="colorChanged:" target="-2" id="3vl-pH-esq"/>
</connections>
</colorWell>
<colorWell id="53">
<rect key="frame" x="103" y="14" width="44" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="color" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<action selector="colorChanged:" target="-2" id="ljb-zv-K8U"/>
</connections>
</colorWell>
<popUpButton verticalHuggingPriority="750" id="68">
<rect key="frame" x="103" y="74" width="243" height="25"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="roundTextured" title="Item 1" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" selectedItem="71" id="69">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" title="OtherViews" id="70">
<items>
<menuItem title="Item 1" state="on" id="71"/>
<menuItem title="Item 2" id="72"/>
<menuItem title="Item 3" id="73"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="setColorScheme:" target="-2" id="122"/>
</connections>
</popUpButton>
</subviews>
</view>
</box>
<button verticalHuggingPriority="750" misplaced="YES" id="19">
<rect key="frame" x="20" y="18" width="118" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" title="Cancel" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="20">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="cancelButton:" target="-2" id="40"/>
</connections>
</button>
</subviews>
</view>
<contentBorderThickness minY="0.0" maxY="0.0"/>
<connections>
<outlet property="delegate" destination="-2" id="39"/>
</connections>
<point key="canvasLocation" x="116" y="23"/>
</window>
<userDefaultsController representsSharedInstance="YES" id="102"/>
</objects>
</document>

259
Base.lproj/TermConfig.xib Normal file
View File

@ -0,0 +1,259 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
<capability name="box content view" minToolsVersion="7.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="TermWindowController">
<connections>
<outlet property="_bg" destination="y7X-B6-fK7" id="8g8-jL-Hgq"/>
<outlet property="_bloomSlider" destination="zfR-wC-m69" id="NUl-l7-LxH"/>
<outlet property="_blurSlider" destination="HTX-GL-dSw" id="nzS-Rs-opd"/>
<outlet property="_darkenSlider" destination="rzo-AM-xgS" id="cQU-IX-Ayk"/>
<outlet property="_effectsButton" destination="45n-1u-DD3" id="RO9-5L-rw0"/>
<outlet property="_fg" destination="h2m-UV-1jK" id="vUr-6N-hct"/>
<outlet property="_lightenSlider" destination="Yyg-Jb-Ehs" id="VIu-nj-6sy"/>
<outlet property="_vignetteSlider" destination="m3R-Cx-hoV" id="yQC-Hh-YhM"/>
<outlet property="popover" destination="Ezq-gE-d2Y" id="kjM-1e-QEy"/>
<outlet property="popoverViewController" destination="OVV-qD-BBZ" id="GrG-Nb-XmA"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<viewController id="OVV-qD-BBZ" userLabel="Popover View Controller">
<connections>
<outlet property="view" destination="I75-XO-Tcx" id="wDA-e4-3DT"/>
</connections>
</viewController>
<popover behavior="semitransient" id="Ezq-gE-d2Y">
<connections>
<outlet property="contentViewController" destination="OVV-qD-BBZ" id="0a5-yM-Gvw"/>
<outlet property="delegate" destination="-2" id="kCQ-Mx-dwQ"/>
</connections>
</popover>
<view misplaced="YES" id="I75-XO-Tcx">
<rect key="frame" x="0.0" y="0.0" width="480" height="386"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<box autoresizesSubviews="NO" misplaced="YES" borderType="line" title="Colors" id="9nf-mJ-BR9">
<rect key="frame" x="-3" y="214" width="486" height="152"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<view key="contentView" id="Yk4-q6-pft">
<rect key="frame" x="1" y="1" width="484" height="136"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="FUz-bX-GbP">
<rect key="frame" x="15" y="76" width="83" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Foreground:" id="xJP-lw-Tbc">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="dnI-BK-Rcv">
<rect key="frame" x="15" y="107" width="83" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Scheme:" id="KcE-bJ-jXO">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="bBS-WW-w8G">
<rect key="frame" x="15" y="45" width="83" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Background:" id="yQ3-OB-2JZ">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<colorWell misplaced="YES" tag="101" id="h2m-UV-1jK">
<rect key="frame" x="103" y="73" width="44" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="color" red="0.0" green="1" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="3Ru-PH-hSQ"/>
<binding destination="-2" name="value" keyPath="foregroundColor" id="rBL-Ts-HGk"/>
</connections>
</colorWell>
<colorWell tag="102" id="y7X-B6-fK7">
<rect key="frame" x="103" y="42" width="44" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="color" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="R4l-cG-wwp"/>
<binding destination="-2" name="value" keyPath="backgroundColor" id="bvR-yG-ANl"/>
</connections>
</colorWell>
<popUpButton verticalHuggingPriority="750" id="3sV-7a-zHB">
<rect key="frame" x="103" y="102" width="363" height="25"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="roundTextured" title="Item 1" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" selectedItem="Fvo-nW-HxK" id="4D2-1v-aHi">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" title="OtherViews" id="MbT-U8-boD">
<items>
<menuItem title="Item 1" state="on" id="Fvo-nW-HxK"/>
<menuItem title="Item 2" id="M9V-09-Hcy"/>
<menuItem title="Item 3" id="Fc7-mh-zWC"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<button verticalHuggingPriority="750" misplaced="YES" id="KyB-fP-aHS">
<rect key="frame" x="103" y="10" width="75" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" title="Swap" bezelStyle="texturedRounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="jAf-VI-BPe">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="swapColors:" target="-2" id="chW-So-Y92"/>
</connections>
</button>
</subviews>
</view>
</box>
<box autoresizesSubviews="NO" misplaced="YES" borderType="line" title="Effects" id="KgG-2I-L3k">
<rect key="frame" x="-3" y="11" width="486" height="199"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<view key="contentView" id="Ugn-Ms-tK7">
<rect key="frame" x="1" y="1" width="484" height="183"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<slider verticalHuggingPriority="750" id="HTX-GL-dSw">
<rect key="frame" x="85" y="131" width="383" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" tickMarkPosition="above" sliderType="linear" id="L90-Mv-v8n"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="f7g-CF-VXa"/>
<binding destination="-2" name="value" keyPath="blurValue" id="D5Z-q9-Rlv"/>
<binding destination="-2" name="enabled" keyPath="effectsEnabled" id="zaD-eS-SmB"/>
</connections>
</slider>
<slider verticalHuggingPriority="750" id="Yyg-Jb-Ehs">
<rect key="frame" x="85" y="79" width="383" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" doubleValue="0.25" tickMarkPosition="above" sliderType="linear" id="u6M-Gg-qBE"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="x62-Id-NWe"/>
<binding destination="-2" name="value" keyPath="backlightValue" id="VfT-3v-Gax"/>
<binding destination="-2" name="enabled" keyPath="effectsEnabled" id="PUq-u9-d6F"/>
</connections>
</slider>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="H0z-mE-bY7">
<rect key="frame" x="25" y="134" width="56" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Blur:" id="JNK-dk-099">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="Z01-Bk-h4V">
<rect key="frame" x="17" y="84" width="64" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Backlight:" id="5mr-bX-5bG">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="q1N-n8-Z3T">
<rect key="frame" x="15" y="59" width="66" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Scanlines:" id="7S4-8E-SbL">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<slider verticalHuggingPriority="750" id="rzo-AM-xgS">
<rect key="frame" x="85" y="56" width="383" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" doubleValue="0.5" tickMarkPosition="above" sliderType="linear" id="938-Rg-ZhB"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="I4v-8E-7m0"/>
<binding destination="-2" name="enabled" keyPath="effectsEnabled" id="lKZ-pD-cDA"/>
<binding destination="-2" name="value" keyPath="scanlineValue" id="jM9-zH-7OX"/>
</connections>
</slider>
<slider verticalHuggingPriority="750" id="m3R-Cx-hoV">
<rect key="frame" x="85" y="31" width="383" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" doubleValue="1" tickMarkPosition="above" sliderType="linear" id="XLJ-uB-JVF"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="UIJ-Xs-mea"/>
<binding destination="-2" name="enabled" keyPath="effectsEnabled" id="xHh-22-Gmn"/>
<binding destination="-2" name="value" keyPath="vignetteValue" id="MOU-47-YUb"/>
</connections>
</slider>
<button id="45n-1u-DD3">
<rect key="frame" x="83" y="157" width="118" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Effects Enabled" bezelStyle="regularSquare" imagePosition="left" alignment="left" state="on" inset="2" id="4dP-ze-wtI">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="filterParameterChanged:" target="-2" id="92u-Vv-Leg"/>
<binding destination="-2" name="value" keyPath="effectsEnabled" id="hEB-Mh-eRD"/>
</connections>
</button>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="V15-3Z-rcp">
<rect key="frame" x="33" y="109" width="46" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Bloom:" id="hao-V0-JkY">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<slider verticalHuggingPriority="750" id="zfR-wC-m69">
<rect key="frame" x="83" y="106" width="383" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" doubleValue="0.75" tickMarkPosition="above" sliderType="linear" id="KU3-BX-dWp"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="IxY-Oe-aaz"/>
<binding destination="-2" name="value" keyPath="bloomValue" id="3cg-US-D8y"/>
<binding destination="-2" name="enabled" keyPath="effectsEnabled" id="pKA-B0-P4C"/>
</connections>
</slider>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" id="oc8-uX-jXl">
<rect key="frame" x="20" y="33" width="59" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Vignette:" id="kD4-LV-p7U">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
</box>
<button misplaced="YES" id="b5f-6s-ZI2">
<rect key="frame" x="451" y="357" width="24" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="TabClose" imagePosition="only" alignment="center" alternateImage="TabClose_Pressed" inset="2" id="Fi8-z7-gn2">
<behavior key="behavior" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="performClose:" target="Ezq-gE-d2Y" id="CcO-2x-8Vw"/>
</connections>
</button>
</subviews>
<point key="canvasLocation" x="-521" y="413"/>
</view>
<userDefaultsController representsSharedInstance="YES" id="mq9-aV-tAe"/>
</objects>
<resources>
<image name="TabClose" width="12" height="13"/>
<image name="TabClose_Pressed" width="12" height="13"/>
</resources>
</document>

View File

@ -1,13 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="TermWindowController">
<connections>
<outlet property="colorView" destination="2" id="3TK-Yg-hmS"/>
<outlet property="emulatorView" destination="5" id="14"/>
<outlet property="_colorView" destination="2" id="QiD-Qe-7pg"/>
<outlet property="_emulatorView" destination="5" id="JNn-UY-fjw"/>
<outlet property="window" destination="1" id="3"/>
</connections>
</customObject>
@ -44,5 +46,6 @@
<outlet property="textLabel" destination="jhD-Y5-62e" id="Zzx-CJ-wV8"/>
</connections>
</window>
<userDefaultsController representsSharedInstance="YES" id="mq9-aV-tAe"/>
</objects>
</document>

View File

@ -8,15 +8,24 @@
#import <Cocoa/Cocoa.h>
enum {
CGApple80,
CGApple40,
CGVT52,
CGVT100
};
@interface CharacterGenerator : NSObject
{
CGImageRef _image;
NSMutableArray *_characters;
NSImage *_image;
NSImage *_characters[256];
NSSize _size;
}
+(CharacterGenerator *)generator;
+(CharacterGenerator *)generatorForCharacterSet: (unsigned)characterSet;
@property (nonatomic, readonly) NSSize characterSize;

View File

@ -10,10 +10,16 @@
#import "CharacterGenerator.h"
@interface CharacterGenerator ()
-(void)loadImageNamed: (NSString *)imageName;
-(id)initWithImageNamed: (NSString *)imageName;
@end
@implementation CharacterGenerator
@synthesize characterSize = _size;
#if 0
static CGImageRef PNGImage(NSString *path)
{
CGImageRef image = NULL;
@ -31,89 +37,117 @@ static CGImageRef PNGImage(NSString *path)
return image;
}
#endif
+(CharacterGenerator *)generatorForCharacterSet: (unsigned)characterSet {
static CharacterGenerator *singletons[4] = {};
static NSString *names[] = {
@"a2-charset-80",
@"a2-charset-40",
@"vt52-charset",
@"vt100-charset",
};
constexpr unsigned MaxCharSet = sizeof(names) / sizeof(names[0]);
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
for (unsigned i = 0; i < MaxCharSet; ++i)
singletons[i] = [[CharacterGenerator alloc] initWithImageNamed: names[i]];
});
if (characterSet >= MaxCharSet) return nil;
return singletons[characterSet];
}
+(id)generator
{
return [[self new] autorelease];
return [self generatorForCharacterSet: CGApple80];
}
-(id)init
{
-(id)initWithImageNamed: (NSString *)imageName {
if ((self = [super init]))
{
NSBundle *mainBundle;
NSString *imagePath;
CGImageRef mask;
CGImageRef src;
NSSize size;
mainBundle = [NSBundle mainBundle];
imagePath = [mainBundle pathForResource: @"a2-charset-80" ofType: @"png"];
//imagePath = [mainBundle pathForResource: @"vt100-charset" ofType: @"png"];
//imagePath = [mainBundle pathForResource: @"vt52-charset" ofType: @"png"];
_characters = [[NSMutableArray alloc] initWithCapacity: 256];
_size = NSMakeSize(7, 16);
src = PNGImage(imagePath);
size.width = CGImageGetWidth(src);
size.height = CGImageGetHeight(src);
size.width /= 16;
size.height /= 16;
_size = size;
if (src)
{
mask = CGImageMaskCreate(CGImageGetWidth(src),
CGImageGetHeight(src),
CGImageGetBitsPerComponent(src),
CGImageGetBitsPerPixel(src),
CGImageGetBytesPerRow(src),
CGImageGetDataProvider(src),
NULL, NO);
for (unsigned i = 0; i < 16; ++i)
{
for (unsigned j = 0; j < 16; ++j)
{
CGImageRef cgimg = CGImageCreateWithImageInRect(mask, CGRectMake(j * _size.width, i * _size.height, _size.width, _size.height));
NSImage *nsimg = [[NSImage alloc] initWithCGImage: cgimg size: _size];
[_characters addObject: nsimg];
CGImageRelease(cgimg);
[nsimg release];
}
}
CGImageRelease(src);
CGImageRelease(mask);
}
{
[self loadImageNamed: imageName];
}
return self;
}
/*
* This loads the image then split it up into 256 images.
*
* All representations are handled so it retins any @2x artwork.
*
*/
-(void)loadImageNamed:(NSString *)imageName {
_image = [[NSImage imageNamed: imageName] retain];
_size = [_image size];
_size.width /= 16;
_size.height /= 16;
for (unsigned i = 0; i < sizeof(_characters) / sizeof(_characters[0]); ++i)
_characters[i] = [[NSImage alloc] initWithSize: _size];
for (NSImageRep *rep in [_image representations]) {
CGImageRef mask;
CGImageRef src;
NSSize size;
/* src will auto release */
src = [rep CGImageForProposedRect: NULL context: nil hints: nil];
size.width = CGImageGetWidth(src) / 16;
size.height = CGImageGetHeight(src) / 16;
mask = CGImageMaskCreate(CGImageGetWidth(src),
CGImageGetHeight(src),
CGImageGetBitsPerComponent(src),
CGImageGetBitsPerPixel(src),
CGImageGetBytesPerRow(src),
CGImageGetDataProvider(src),
NULL, NO);
for (unsigned i = 0; i < 16; ++i)
{
for (unsigned j = 0; j < 16; ++j)
{
CGImageRef cgimg = CGImageCreateWithImageInRect(mask, CGRectMake(j * size.width, i * size.height, size.width, size.height));
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage: cgimg];
NSImage *nsimg = _characters[i * 16 + j];
[nsimg addRepresentation: rep];
[rep release];
CGImageRelease(cgimg);
}
}
CGImageRelease(mask);
}
}
-(void)dealloc
{
if (_image) CGImageRelease(_image);
[_characters release];
[_image release];
for (auto &o : _characters) [o release];
[super dealloc];
}
@ -121,14 +155,17 @@ static CGImageRef PNGImage(NSString *path)
-(NSImage *)imageForCharacter: (unsigned)character
{
if (character > [_characters count]) return nil;
if (character >= sizeof(_characters) / sizeof(_characters[0])) return nil;
return (NSImage *)[_characters objectAtIndex: character];
return _characters[character];
}
-(void)drawCharacter: (unsigned)character atPoint: (NSPoint)point
{
NSImage *img = [self imageForCharacter: character];
if (character >= sizeof(_characters) / sizeof(_characters[0])) return;
NSImage *img = _characters[character];
if (!img) return;

21
ChildMonitor.h Normal file
View File

@ -0,0 +1,21 @@
//
// ChildMonitor.h
// TwoTerm
//
// Created by Kelvin Sherlock on 1/31/2018.
//
#import <Foundation/Foundation.h>
@class TermWindowController;
@interface ChildMonitor : NSObject {
}
+(id)monitor;
-(void)removeController: (TermWindowController *)controller;
-(void)addController: (TermWindowController *)controller pid: (pid_t)pid fd: (int)fd;
-(void)removeAll;
@end

255
ChildMonitor.mm Normal file
View File

@ -0,0 +1,255 @@
//
// ChildMonitor.m
// TwoTerm
//
// Created by Kelvin Sherlock on 1/31/2018.
//
#import "ChildMonitor.h"
#import "TermWindowController.h"
#include "Lock.h"
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <vector>
#include <algorithm>
namespace {
struct entry {
pid_t pid;
int fd;
TermWindowController *controller;
};
typedef std::vector<entry> entry_vector;
entry_vector::iterator find_controller(entry_vector &table, TermWindowController *controller) {
return std::find_if(table.begin(), table.end(), [=](const entry &e){
return e.controller == controller;
});
}
entry_vector::iterator find_pid(entry_vector &table, pid_t pid) {
return std::find_if(table.begin(), table.end(), [=](const entry &e){
return e.pid == pid;
});
}
entry_vector::iterator find_fd(entry_vector &table, int fd) {
return std::find_if(table.begin(), table.end(), [=](const entry &e){
return e.fd == fd;
});
}
/* return NO on EOF */
BOOL read(int fd, TermWindowController *controller) {
size_t total = 0;
for (;;) {
uint8_t buffer[2048];
ssize_t ok = ::read(fd, buffer, sizeof(buffer));
if (ok == 0) return total > 0;
if (ok < 1) {
if (errno == EINTR) continue;
if (errno == EAGAIN) return YES;
return YES;
}
[controller processData: buffer size: ok];
if (ok < sizeof(buffer)) return YES;
total += ok;
}
}
}
@interface ChildMonitor() {
std::vector<entry> _table;
int _kq;
Lock _lock;
}
@end
@implementation ChildMonitor
+(id)monitor {
static ChildMonitor *me = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
me = [ChildMonitor new];
[NSThread detachNewThreadSelector: @selector(run) toTarget: me withObject: nil];
});
return me;
}
-(id)init {
if ((self = [super init])) {
_kq = kqueue();
}
return self;
}
-(void)dealloc {
_lock.lock();
close(_kq);
for (const auto &e : _table) {
if (e.fd >= 0) close(e.fd);
if (e.pid > 0) kill(e.pid, SIGHUP);
if (e.controller) [e.controller release];
}
_lock.unlock();
[super dealloc];
}
-(void)removeAll {
Locker l(_lock);
for (auto &e : _table) {
if (e.controller) {
[e.controller release];
e.controller = nil;
}
if (e.pid > 0) {
kill(e.pid, SIGHUP);
e.pid = -1;
}
}
}
-(void)removeController: (TermWindowController *)controller {
if (!controller) return;
Locker l(_lock);
auto iter = find_controller(_table, controller);
if (iter != _table.end()) {
[iter->controller release];
iter->controller = nil;
if (iter->pid > 0) kill(iter->pid, SIGHUP);
}
}
-(void)addController: (TermWindowController *)controller pid: (pid_t)pid fd: (int)fd {
NSLog(@"Adding pid: %d fd: %d", pid, fd);
int flags;
// non-blocking io.
if (fcntl(fd, F_GETFL, &flags) < 0) flags = 0;
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
Locker l(_lock);
_table.emplace_back(entry{pid, fd, [controller retain]});
struct kevent events[2] = {};
EV_SET(&events[0], fd, EVFILT_READ, EV_ADD | EV_RECEIPT, 0, 0, NULL);
EV_SET(&events[1], pid, EVFILT_PROC, EV_ADD | EV_ONESHOT | EV_RECEIPT, NOTE_EXIT | NOTE_EXITSTATUS, 0, NULL);
kevent(_kq, events, 2, NULL, 0, NULL);
}
-(void) run {
struct kevent events[16] = {};
for(;;) {
@autoreleasepool {
int n = kevent(_kq, NULL, 0, events, 2, NULL);
if (n < 0) {
NSLog(@"kevent: %s", strerror(errno));
continue;
}
if (n == 0) {
continue;
}
Locker l(_lock);
// should process twice, first for reading, second for dead children.
std::for_each(events, events + n, [&](const struct kevent &e){
if (e.filter != EVFILT_READ) return;
int fd = (int)e.ident;
if (e.flags & EV_EOF) {
NSLog(@"EV_EOF %d", fd);
return;
}
if (e.flags & EV_ERROR) {
NSLog(@"EV_ERROR %d", fd);
return;
}
auto iter = find_fd(_table, fd);
if (iter == _table.end() || iter->controller == nil) {
NSLog(@"Closing fd %d (not found)", fd);
close(fd); // should automatically remove itself from kevent
iter->fd = -1;
} else {
BOOL ok = read(fd, iter->controller);
if (!ok) {
NSLog(@"Closing fd %d (eof)", fd);
close(fd); // should automatically remove itself from kevent
iter->fd = -1;
}
}
});
std::for_each(events, events + n, [&](const struct kevent &e){
if (e.filter != EVFILT_PROC) return;
pid_t pid = (pid_t)e.ident;
int status = 0;
for(;;) {
int ok = waitpid(pid, &status, WNOHANG);
if (ok >= 0) break;
if (errno == EINTR) continue;
NSLog(@"waitpid(%d): %s", pid, strerror(errno));
break;
}
auto iter = find_pid(_table, pid);
if (iter == _table.end()) {
} else {
if (iter->fd >= 0) {
// check for pending i/o ?
if (iter->controller)
read(iter->fd, iter->controller);
NSLog(@"Closing fd %d (child exited)", iter->fd);
close(iter->fd);
iter->fd = -1;
}
[iter->controller childFinished: status];
[iter->controller release];
iter->controller = nil;
*iter = std::move(_table.back());
_table.pop_back();
}
NSLog(@"Child %d finished", pid);
});
}
}
}
@end

24
Defaults.plist Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>Name</key>
<string>Green Black</string>
<key>Foreground</key>
<integer>65280</integer>
<key>Background</key>
<integer>0</integer>
<key>Effects</key>
<false/>
<key>Bloom</key>
<integer>0</integer>
<key>Backlight</key>
<integer>0</integer>
<key>Scanlines</key>
<integer>0</integer>
<key>Vignette</key>
<integer>0</integer>
</dict>
</array>
</plist>

33
Emulators/Apple3.h Normal file
View File

@ -0,0 +1,33 @@
//
// Apple3.h
// 2Term
//
// Created by Kelvin Sherlock on 12/24/2018.
// Copyright 2018 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "Emulator.h"
#include "iGeometry.h"
#include "Screen.h"
struct iii_context : public context {
unsigned cursor_control = 0b1101;
unsigned fg_color = 0;
unsigned bg_color = 0;
unsigned mode = 2;
};
@interface Apple3 : NSObject <Emulator>
{
unsigned cs;
iii_context _context;
iii_context _saved_context;
Screen::CursorType _cursorType;
}
@end

466
Emulators/Apple3.mm.ragel Normal file
View File

@ -0,0 +1,466 @@
//
// Apple3.mm
// 2Term
//
// Created by Kelvin Sherlock on 12/24/2018.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
/*
* See Apple III Standard Device Drivers Manual (ch 3, The Console Driver)
* Also implemented via AppleWorks (which started life as III EZ Pieces)
*
* Apple III console can be 24 x 40 (BW), 24 x 40 (16 color), or 24 x 80 (BW).
*
*/
#import "Apple3.h"
#include <sys/ttydefaults.h>
#include "OutputChannel.h"
#include "Screen.h"
#include "algorithm.h"
#import "CharacterGenerator.h"
enum {
kAdvance = 1 << 0,
kLineFeed = 1 << 1,
kWrap = 1 << 2,
kScroll = 1 << 3,
};
%%{
machine console;
alphtype unsigned int;
action nop {}
action advance {
// advance cursor
if (_context.cursor_control & kAdvance) {
switch (_context.cursor_control & (kWrap | kScroll)) {
default:
if (cursor.x < window.maxX() - 1) ++cursor.x;
break;
case kWrap:
if (cursor.x < window.maxX() - 1) ++cursor.x;
else {
cursor.x = window.minX();
if (cursor.y < window.maxY() - 1) ++cursor.y;
}
break;
case kWrap | kScroll:
if (cursor.x < window.maxX() - 1) ++cursor.x;
else {
cursor.x = window.minX();
if (cursor.y < window.maxY() - 1) ++cursor.y;
else screen->scrollUp(window);
}
break;
}
}
}
action setx {
/* horizontal position */
int x = (unsigned)fc;
x += window.minX();
cursor.x = std::min(x, window.maxX() - 1);
}
action sety {
/* vertical position */
int y = (unsigned)fc;
y += window.minY();
cursor.y = std::min(y, window.maxY() - 1);
}
# arg1 = any ${ _scratch[0] = fc; };
# arg2 = any ${ _scratch[1] = fc; };
main := (
0x00 $nop
| 0x01 ${
/* save viewport and reset */
_saved_context = _context;
window = iRect(0, 0, 80, 24);
/* currently ignores mode */
}
| 0x02 ${
/* set viewport top */
iPoint tl = cursor;
iPoint br = window.bottomRight();
_context.window = iRect(tl, br);
}
| 0x03 ${
/* set viewport bottom */
iPoint tl = _context.window.topLeft();
iPoint br = _context.cursor.offset(1,1);
_context.window = iRect(tl, br);
}
| 0x04 ${
/* restore viewport */
_context = _saved_context;
}
| 0x05 ${
/* E - $05 - Turns cursor on (enables cursor display) */
screen->setCursorType(Screen::CursorTypeUnderscore);
}
| 0x06 ${
/* F - $06 - Turns cursor off (disables cursor display) */
screen->setCursorType(Screen::CursorTypeNone);
}
| 0x07 ${
/* Beep */
NSBeep();
}
| 0x08 ${
/* Moves cursor left */
if (cursor.x > window.minX()) --cursor.x;
else if (_context.cursor_control & kWrap) {
cursor.x = window.maxX() - 1;
if (cursor.y > window.minY()) --cursor.y;
else if (_context.cursor_control & kScroll) {
screen->scrollDown(window);
}
}
}
| 0x09 ${
/* move cursor right */
if (cursor.x < window.maxX()-1) ++cursor.x;
else if (_context.cursor_control & kWrap) {
cursor.x = window.minX();
if (cursor.y < window.maxY()-1) ++cursor.y;
else if (_context.cursor_control & kScroll) {
screen->scrollUp(window);
}
}
}
| 0x0a ${
/* move cursor down */
if (cursor.y < window.maxY() - 1) ++cursor.y;
else if (_context.cursor_control & kScroll) {
screen->scrollUp(window);
}
}
| 0x0b ${
/* move cursor up */
if (cursor.y > window.minY()) --cursor.y;
else if (_context.cursor_control & kScroll) {
screen->scrollDown(window);
}
}
| 0x0c ${
/* home */
cursor = iPoint(window.topLeft());
}
| 0x0d ${
/* carriage return */
/* also LF depending on cursor motion */
cursor.x = window.minX();
if (_context.cursor_control & kLineFeed) {
if (cursor.y < window.maxY() - 1) ++cursor.y;
else if (_context.cursor_control & kScroll) {
screen->scrollUp(window);
}
}
}
| 0x0e ${
/* turn screen off ... */
}
| 0x0f ${
/* turn screen on ... */
}
| 0x10 any ${
/* set text mode (40 vs 80, color vs bw) */
_context.mode = fc & 0x03;
}
| 0x11 ${
/* normal text */
_context.clearFlagBit(Screen::FlagInverse);
}
| 0x12 ${
/* invert text */
_context.setFlagBit(Screen::FlagInverse);
}
| 0x13 any ${
/* set foreground text color */
_context.fg_color = fc & 0x0f;
}
| 0x14 any ${
/* set background text color */
_context.bg_color = fc & 0x0f;
}
| 0x15 any ${
/* set cursor motion control */
_context.cursor_control = fc & 0x0f;
}
# sync
| 0x16 $nop
| 0x17 any ${
/* horizontal shift */
int count = (int8_t)fc;
/* if > 0, shift right */
if (count > 0) screen->scrollRight(window, count);
/* if < 0, shift left */
if (count < 0) screen->scrollLeft(window, -count);
}
# horizontal position
| 0x18 any $setx
# vertical position
| 0x19 any $sety
# horizontal + vertical position
| 0x1a any $setx any $sety
# esc - reserved
| 0x1b $nop
| 0x1c ${
/* HOME + clear viewport */
cursor = window.topLeft();
screen->eraseRect(window);
}
| 0x1d ${
/* clear to end of viewport */
iRect r(cursor, window.bottomRight());
r.size.height = 1;
screen->eraseRect(r);
r = iRect(window.minX(), cursor.y + 1, window.width(), window.maxY() - cursor.y - 1);
screen->eraseRect(r);
}
| 0x1e ${
/* move to left edge of viewport, clear line */
cursor.y = window.minY();
iRect r(cursor, window.bottomRight());
r.size.height = 1;
screen->eraseRect(r);
}
| 0x1f ${
/* clear to end of line */
iRect r(cursor, window.bottomRight());
r.size.height = 1;
screen->eraseRect(r);
}
| 0x20 .. 0x7f ${
screen->putc(fc, _context);
} $advance
| 0x80 .. 0x9f ${
/* display control char? */
}
| 0xa0 .. 0xff ${
screen->putc(fc & 0x7f, _context);
} $advance
)* $err{ fgoto main; };
write data;
}%%
@implementation Apple3
+(void)load {
[EmulatorManager registerClass: self];
}
- (NSString *)name {
return @"Apple III";
}
+ (NSString *)name {
return @"Apple III";
}
- (const char *)termName {
return "appleIII";
}
-(void)reset: (BOOL)hard
{
%%write init;
_context.flags = 0;
_cursorType = Screen::CursorTypeUnderscore;
_context.fg_color = 15; /* white */
_context.bg_color = 0; /* black */
_context.cursor_control = kScroll | kWrap | kAdvance;
if (hard) {
_context.window = iRect(0, 0, 80, 24);
_context.cursor = iPoint(0,0);
_context.mode = 2;
_saved_context = iii_context();
}
}
-(BOOL)resizable
{
return NO;
}
-(struct winsize)defaultSize
{
struct winsize ws = { 24, 80, 0, 0 };
return ws;
}
-(void)initTerm: (struct termios *)term
{
// Control-U is used by the up-arrow key.
term->c_cc[VKILL] = CTRL('X');
// tab is right arrow, so expand to spaces.
term->c_oflag |= OXTABS;
}
-(id)init
{
if ((self = [super init]))
{
[self reset: YES];
}
return self;
}
-(void)processData:(uint8_t *)data length: (size_t)length screen:(Screen *)screen output:(OutputChannel *)output
{
const uint8_t *eof = nullptr;
const uint8_t *p = data;
const uint8_t *pe = data + length;
auto &cursor = _context.cursor;
auto &window = _context.window;
auto &cursor_control = _context.cursor_control;
%%write exec;
screen->setCursor(cursor);
}
-(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output
{
NSEventModifierFlags flags = [event modifierFlags];
NSString *chars = [event charactersIgnoringModifiers];
NSUInteger length = [chars length];
for (unsigned i = 0; i < length; ++i)
{
unichar uc = [chars characterAtIndex: i];
switch (uc)
{
case NSEnterCharacter:
output->write(CTRL('M'));
break;
/*
case NSDeleteCharacter:
output->write(0x7f);
break;
*/
// the Apple II keyboard had a delete where the backspace key was.
// it functions as a backspace key.
case NSBackspaceCharacter:
output->write(0x7f);
break;
case NSLeftArrowFunctionKey:
output->write(CTRL('H'));
break;
case NSRightArrowFunctionKey:
output->write(CTRL('U'));
break;
case NSUpArrowFunctionKey:
output->write(CTRL('K'));
break;
case NSDownArrowFunctionKey:
output->write(CTRL('J'));
break;
default:
if (uc <= 0x7f)
{
char c = uc;
//NSLog(@"%@", event);
if (flags & NSAlphaShiftKeyMask)
{
c = flags & NSShiftKeyMask ? tolower(c) : toupper(c);
}
if (flags & NSControlKeyMask)
c = CTRL(c);
output->write(c);
}
break;
}
}
}
@end

View File

@ -12,12 +12,19 @@
#include "iGeometry.h"
#include "Screen.h"
@interface Apple80 : NSObject <Emulator> {
@interface AppleX : NSObject <Emulator> {
unsigned cs;
unsigned _columns;
int _scratch[4];
context _context;
}
@end
@interface Apple40 : AppleX
@end
@interface Apple80 : AppleX
@end

View File

@ -21,6 +21,7 @@
#include "Screen.h"
#include "algorithm.h"
#import "CharacterGenerator.h"
%%{
machine console;
@ -30,7 +31,7 @@
action advance {
// advance cursor
if (++cursor.x == 80) {
if (++cursor.x == _columns) {
cursor.x = 0;
if (cursor.y >= 24-1) {
screen->scrollUp();
@ -74,7 +75,7 @@
if (cursor.x) cursor.x--;
else {
cursor.x = 80-1;
cursor.x = _columns-1;
// go up, possibly scrolling.
if (cursor.y) cursor.y--;
}
@ -101,11 +102,11 @@
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(80 - cursor.x, 1);
tmp.size = iSize(_columns - cursor.x, 1);
screen->eraseRect(tmp);
tmp = iRect(0, 0, 80, 24);
tmp = iRect(0, 0, _columns, 24);
tmp.origin.y = cursor.y+1;
tmp.size.height -= cursor.y+1;
screen->eraseRect(tmp);
@ -172,7 +173,7 @@
/* clear line */
iRect tmp;
tmp.origin = iPoint(0, cursor.y);
tmp.size = iSize(80, 1);
tmp.size = iSize(_columns, 1);
screen->eraseRect(tmp);
}
@ -187,7 +188,7 @@
/* Moves cursor right one column; if at end of line, does Control-M */
// n.b. - BASIC ^M also moves to next line.
cursor.x++;
if (cursor.x == 80) cursor.x = 0;
if (cursor.x == _columns) cursor.x = 0;
}
| 0x1d ${
@ -195,7 +196,7 @@
/* clear to end of line */
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(80 - cursor.x, 1);
tmp.size = iSize(_columns - cursor.x, 1);
screen->eraseRect(tmp);
}
@ -204,7 +205,7 @@
// CTRL('^'):
/* goto x y */
// todo - verify behavior for illegal values.
cursor.x = clamp(_scratch[0], 0, 80 - 1);
cursor.x = clamp(_scratch[0], 0, (int)_columns - 1);
cursor.y = clamp(_scratch[1], 0, 24 - 1);
}
@ -220,26 +221,26 @@
| 0x80 .. 0x9f ${
/* uppercase inverse/normal */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
uint8_t flag = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x40, _context.cursor, flag);
} $advance
| 0xa0 .. 0xbf ${
/* special inverse/normal */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
uint8_t flag = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x80, _context.cursor, flag);
} $advance
| 0xc0 .. 0xdf ${
/* uppercase normal / mouse text. */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
uint8_t flag = _context.flags ^ Screen::FlagInverse;
if (flag) flag |= Screen::FlagMouseText;
screen->putc(fc - 0x80, _context.cursor, flag);
} $advance
| 0xe0 .. 0xff ${
/* special inverse/normal */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
uint8_t flag = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x80, _context.cursor, flag);
} $advance
@ -248,37 +249,35 @@
write data;
}%%
@implementation Apple80
@implementation AppleX
+(void)load
{
[EmulatorManager registerClass: self];
- (NSString *)name {
return @"Apple X";
}
+(NSString *)name
{
return @"Apple 80";
+ (NSString *)name {
return @"Apple X";
}
-(NSString *)name
{
return @"Apple 80";
}
-(const char *)termName
{
- (const char *)termName {
return "appleIIe";
}
-(void)reset
-(void)reset: (BOOL)hard
{
%%write init;
_context.window = iRect(0, 0, 80, 24);
_context.cursor = iPoint(0,0);
_context.flags = 0;
if (hard) {
_context.window = iRect(0, 0, _columns, 24);
_context.cursor = iPoint(0,0);
}
}
-(BOOL)resizable
@ -288,7 +287,7 @@
-(struct winsize)defaultSize
{
struct winsize ws = { 24, 80, 0, 0 };
struct winsize ws = { 24, (unsigned short)_columns, 0, 0 };
return ws;
}
@ -303,7 +302,7 @@
{
if ((self = [super init]))
{
[self reset];
[self reset: YES];
}
return self;
@ -393,4 +392,70 @@
}
}
@end
@implementation Apple40
+(void)load
{
[EmulatorManager registerClass: self];
}
+(NSString *)name
{
return @"Apple 40";
}
-(NSString *)name
{
return @"Apple 40";
}
-(const char *)termName
{
return "appleIIe";
}
-(void) reset: (BOOL)hard {
_columns = 40;
[super reset: hard];
}
-(CharacterGenerator *)characterGenerator {
return [CharacterGenerator generatorForCharacterSet: CGApple40];
}
@end
@implementation Apple80
+(void)load
{
[EmulatorManager registerClass: self];
}
+(NSString *)name
{
return @"Apple 80";
}
-(NSString *)name
{
return @"Apple 80";
}
-(const char *)termName
{
return "appleIIe";
}
-(void) reset: (BOOL)hard {
_columns = 80;
[super reset: hard];
}
@end

View File

@ -28,6 +28,7 @@ extern "C" unsigned EventCharacters(NSEvent *event, std::u32string &rv);
#import "iGeometry.h"
@class CharacterGenerator;
@interface EmulatorManager : NSObject
@ -49,7 +50,7 @@ extern "C" unsigned EventCharacters(NSEvent *event, std::u32string &rv);
-(void)keyDown: (NSEvent *)event screen: (Screen *)screen output: (OutputChannel *)output;
-(void)reset;
-(void)reset: (BOOL)hard;
+(NSString *)name;
-(NSString *)name;
@ -63,5 +64,6 @@ extern "C" unsigned EventCharacters(NSEvent *event, std::u32string &rv);
@optional
-(void)initTerm: (struct termios *)term;
-(CharacterGenerator *)characterGenerator;
@end

View File

@ -129,7 +129,6 @@
screen->scrollUp(window);
} else cursor.y++;
}
}
arg1 = any ${ _scratch[0] = ((fc & 0x7f) - 32); };
@ -411,19 +410,19 @@
}
-(void)reset
-(void)reset: (BOOL)hard
{
%%write init;
_context.flags = 0;
_context.window = iRect(0, 0, 80, 24);
_context.cursor = iPoint(0,0);
_cursorType = Screen::CursorTypeUnderscore;
// set flags to plain text.
if (hard) {
_context.window = iRect(0, 0, 80, 24);
_context.cursor = iPoint(0,0);
}
}
-(BOOL)resizable
@ -448,7 +447,7 @@
{
if ((self = [super init]))
{
[self reset];
[self reset: YES];
}
return self;

View File

@ -420,26 +420,26 @@ static void advance(Screen *screen, gsos_context &ctx) {
| 0x80 .. 0x9f ${
/* uppercase inverse/normal */
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
uint8_t flags = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x40, cursor, flags);
} $advance_if
| 0xa0 .. 0xbf ${
/* special inverse/normal */
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
uint8_t flags = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x80, cursor, flags);
} $advance_if
| 0xc0 .. 0xdf ${
/* uppercase normal / mouse text. */
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
uint8_t flags = _context.flags ^ Screen::FlagInverse;
if (flags) flags |= Screen::FlagMouseText;
screen->putc(fc - 0x80, cursor, flags);
} $advance_if
| 0xe0 .. 0xff ${
/* special inverse/normal */
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
uint8_t flags = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x80, cursor, flags);
} $advance_if
@ -496,20 +496,23 @@ static void advance(Screen *screen, gsos_context &ctx) {
{
if ((self = [super init]))
{
[self reset];
[self reset: YES];
}
return self;
}
-(void)reset
-(void)reset: (BOOL)hard
{
%%write init;
_context.window = iRect(0, 0, 80, 24);
_context.cursor = iPoint(0,0);
if (hard) {
_context_stack.clear();
_context.window = iRect(0, 0, 80, 24);
_context.cursor = iPoint(0,0);
}
_context.consWrap = true;
_context.consAdvance = true;

View File

@ -306,20 +306,15 @@
return "proterm-special";
}
-(void)reset: (Screen *)screen
{
[self reset];
if (screen) screen->eraseScreen();
}
-(void)reset
-(void)reset: (BOOL)hard
{
%%write init;
_context.cursor = iPoint(0,0);
_context.window = iRect(0,0,80,24);
_context.flags = 0;
if (hard) {
_context.cursor = iPoint(0,0);
_context.window = iRect(0,0,80,24);
}
}
-(BOOL)resizable
@ -336,7 +331,7 @@
-(id)init
{
[self reset];
[self reset: YES];
return self;
}

View File

@ -15,11 +15,10 @@
@interface VT05 : NSObject <Emulator> {
unsigned _state;
unsigned cs;
unsigned _scratch[2];
context _context;
BOOL _upperCase;
}
-(void)tab: (Screen *)screen;
@end

236
Emulators/VT05.mm.ragel Normal file
View File

@ -0,0 +1,236 @@
//
// VT05.mm.m
// TwoTerm
//
// Created by Kelvin Sherlock on 3/3/2018.
//
// Disabled because linefeed only scrolls when on the last line... not very useful!
//
//
/*
* http://vt100.net/docs/vt05-rm/contents.html
*/
#include <sys/ttydefaults.h>
#include <cctype>
#import "VT05.h"
#include "OutputChannel.h"
#include "Screen.h"
enum {
VTBell = 07,
VTCursorLeft = 010,
VTTab = 011,
VTLineFeed = 012,
VTCursorDown = 013,
VTCarriageReturn = 015,
VTCAD = 016,
VTCursorRight = 030,
VTCursorUp = 032,
VTHome = 035,
VTEOL = 036,
VTEOS = 037
};
%%{
machine console;
alphtype unsigned int;
action nop {}
action tab {
if (cursor.x < 64) cursor.x = (cursor.x + 8) & ~7;
else if (cursor.x < window.maxX() -1) cursor.x++;
}
action linefeed {
if (cursor.y == window.maxY() -1)
screen->scrollUp();
}
action dca {
unsigned y = _scratch[0];
if (y < window.maxY()) cursor.y = y;
unsigned x = _scratch[1];
if (x < window.maxX()) cursor.x = x;
}
action erase_eos {
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize( window.maxX() - cursor.x, 1);
screen->eraseRect(tmp);
tmp.origin = iPoint(0, cursor.y+1);
tmp.size = iSize(window.maxX(), window.maxY() - cursor.y - 1);
screen->eraseRect(tmp);
}
action erase_eol {
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize( window.maxX() - cursor.x, 1);
screen->eraseRect(tmp);
}
arg1 = 0x00* (any-0x00) ${ _scratch[0] = ((fc & 0x7f) - 32); };
arg2 = 0x00* (any-0x00) ${ _scratch[1] = ((fc & 0x7f) - 32); };
control_codes = (
0x07 ${ NSBeep(); }
| 0x08 ${ if (cursor.x) cursor.x--; }
| 0x09 $tab
| 0x0a $linefeed
| 0x0b ${ if (cursor.y < window.maxY() -1) cursor.y++; }
| 0x0d ${ cursor.x = 0; }
| 0x0e arg1 arg2 $dca
| 0x18 ${ if (cursor.x < window.maxX() -1) cursor.x++; }
| 0x1a ${ if (cursor.y) cursor.y--; }
| 0x1d ${ cursor = iPoint(0,0); }
| 0x1e $erase_eol
| 0x1f $erase_eos
);
main := (
control_codes
| 0x20 .. 0x7e ${
uint8_t c = fc;
if (c & 0x40) c &= ~0x20;
screen->putc(c, _context);
if (cursor.x < window.maxX() - 1) cursor.x++;
}
| any
)** $err{ fgoto main; };
write data;
}%%
@implementation VT05
+(void)load {
[EmulatorManager registerClass: self];
}
+(NSString *)name {
return @"VT05";
}
-(NSString *)name {
return @"VT05";
}
-(const char *)termName {
return "vt05";
}
-(void)reset: (BOOL)hard {
%% write init;
if (hard) {
_context.cursor = iPoint(0,0);
_context.window = iRect(0, 0, 72, 20);
}
}
-(BOOL)resizable {
return NO;
}
-(struct winsize)defaultSize {
struct winsize ws = { 20, 72, 0, 0 };
return ws;
}
-(id)init {
if ((self = [super init])) {
[self reset: YES];
}
return self;
}
-(void)processData: (uint8_t *)data length: (size_t)length screen:(Screen *)screen output:(OutputChannel *)output
{
std::transform(data, data + length, data, [](uint8_t c){ return c & 0x7f; });
const uint8_t *eof = nullptr;
const uint8_t *p = data;
const uint8_t *pe = data + length;
iPoint &cursor = _context.cursor;
const iRect &window = _context.window;
%%write exec;
if (cursor.x == window.maxX()) screen->setCursor(iPoint(window.maxX() - 1, cursor.y));
else screen->setCursor(cursor);
}
-(void)keyDown: (NSEvent *)event screen: (Screen *)screen output: (OutputChannel *)output
{
NSEventModifierFlags flags = [event modifierFlags];
NSString *chars = [event charactersIgnoringModifiers];
NSUInteger length = [chars length];
for (unsigned i = 0; i < length; ++i)
{
unichar uc = [chars characterAtIndex: i];
uint8_t c;
switch (uc)
{
case NSLeftArrowFunctionKey:
output->write(VTCursorLeft);
break;
case NSRightArrowFunctionKey:
output->write(VTCursorRight);
break;
case NSUpArrowFunctionKey:
output->write(VTCursorUp);
break;
case NSDownArrowFunctionKey:
output->write(VTCursorDown);
break;
case NSHomeFunctionKey:
output->write(VTHome);
break;
case NSDeleteCharacter:
output->write(0x7f);
break;
default:
if (uc > 0x7f) break;
c = uc;
if (flags & NSControlKeyMask)
{
c = CTRL(c);
}
output->write(c);
break;
}
}
}
@end

View File

@ -9,35 +9,54 @@
#import <Cocoa/Cocoa.h>
#import "Emulator.h"
#include "iGeometry.h"
#include "Screen.h"
#ifdef __cplusplus
#include <vector>
#include <bitset>
struct vt100_context : public context {
enum {
G0, G1
};
enum {
CharSet_A,
CharSet_B,
CharSet_0,
CharSet_1,
CharSet_2,
};
unsigned G0_charset = CharSet_B;
unsigned G1_charset = CharSet_B;
unsigned charset = G0;
};
#endif
@interface VT100 : NSObject <Emulator> {
unsigned _state;
BOOL _altKeyPad;
unsigned cs;
vt100_context _context;
Screen::CursorType _cursorType;
BOOL _private;
vt100_context _saved_context;
BOOL _keyMode;
BOOL _vt52Mode;
BOOL _graphics;
iPoint _dca;
struct __vt100flags {
unsigned int DECANM:1; // vt52 mode
unsigned int DECANM:1; // ANSI/vt52 mode
unsigned int DECARM:1; // auto repeat mode.
unsigned int DECAWM:1; // autowrap mode
unsigned int DECCKM:1; // cursor key mode.
unsigned int DECKPAM:1; // alternate keypad.
unsigned int DECKPNM:1; // not alternate keypad.
//unsigned int DECKPNM:1; // not alternate keypad.
unsigned int DECCOLM:1; // 80/132 mode.
unsigned int DECSCLM:1; // scrolling
unsigned int DECSCNM:1; // screen
@ -46,17 +65,15 @@
unsigned int LNM:1; // line feed new line mode.
unsigned int VT52GM:1; // vt52 graphics mode
} _flags;
#ifdef __cplusplus
std::vector<int> _parms;
std::vector<unsigned> _args;
std::bitset<80> _tabs;
#endif
}
-(void)tab: (Screen *)screen;
@end

View File

@ -89,8 +89,6 @@ enum {
_flags.DECOM = 0;
_flags.DECINLM = 0;
_flags.LNM = 0;
}

772
Emulators/VT100.mm.ragel Normal file
View File

@ -0,0 +1,772 @@
//
// VT100.mm.ragel
// TwoTerm
//
// Created by Kelvin Sherlock on 4/6/2018.
//
#include <sys/ttydefaults.h>
#include <cctype>
#include <cstdio>
#include <numeric>
#include <algorithm>
#include <utility>
#import "VT100.h"
#include "OutputChannel.h"
#include "Screen.h"
#include "algorithm.h"
#define ESC "\x1b"
%%{
machine vt100;
alphtype unsigned int;
esc = 0x1b;
cancel = 0x30 | 0x32;
action clear_args {
_args.clear();
_args.push_back(0);
}
action answerback {
/* no answerback string */
}
# DECOM - locked to scrolling region
# DECAWM - autowrap
action forward {
if (cursor.x > window_x.second) {
cursor.x = window_x.first;
if (_flags.DECAWM) {
if (cursor_in_region()) {
if (cursor.y == region_y.second)
screen->scrollUp(window);
else {
if (cursor.y < window_y.second) cursor.y++;
}
}
}
}
}
#
# ROM test - scrolling only happens if at bottom of scrolling region.
#
action linefeed {
/*
* ROM test - scrolling ONLY happens if at bottom line of scrolling region.
*
*/
if (cursor.y == region_y.second) {
screen->scrollUp(window);
} else {
cursor.y = std::min(cursor.y + 1u, window_y.second);
}
}
action reverse_linefeed {
if (cursor.y == region_y.first) {
screen->scrollDown(window);
} else {
cursor.y = std::min(cursor.y - 1u, window_y.first);
}
}
#
# ROM TEST - up/down can't escape the scrolling region.
#
action cursor_up {
/* cursor up */
unsigned count = _flags.DECANM ? std::max(1u, _args.front()) : 1;
if (cursor_in_region()) {
cursor.y = clamp(cursor.y - count, region_y.first, region_y.second);
} else {
cursor.y = clamp(cursor.y - count, window_y.first, window_y.second);
}
}
action cursor_down {
/* cursor down */
unsigned count = _flags.DECANM ? std::max(1u, _args.front()) : 1;
if (cursor_in_region()) {
cursor.y = clamp(cursor.y + count, region_y.first, region_y.second);
} else {
cursor.y = clamp(cursor.y + count, window_y.first, window_y.second);
}
}
action cursor_left {
/* cursor left */
unsigned count = _flags.DECANM ? std::max(1u, _args.front()) : 1;
cursor.x = clamp(cursor.x - count, window_x.first, window_x.second);
}
action cursor_right {
/* cursor right */
unsigned count = _flags.DECANM ? std::max(1u, _args.front()) : 1;
cursor.x = clamp(cursor.x + count, window_x.first, window_x.second);
}
action cup {
/* Cursor Position aka DCA */
/* todo - numbering of lines depends on DECOM */
unsigned y = _args.size() > 0 ? _args[0] : 0;
unsigned x = _args.size() > 1 ? _args[1] : 0;
if (x == 0) x = 1;
if (y == 0) y = 1;
if (_flags.DECOM) {
cursor.y = clamp(y - 1 + region_y.first, region_y.first, region_y.second);
cursor.x = clamp(x - 1, window_x.first, window_x.second);
} else {
cursor.y = clamp(y - 1, window_y.first, window_y.second);
cursor.x = clamp(x - 1, window_x.first, window_x.second);
}
}
action vt52_dca {
/* todo - how are invalid values handled? */
/* todo - DECOM supported? */
if (_flags.DECOM) {
cursor.y = clamp(_args[0] + region_y.first, region_y.first, region_y.second);
cursor.x = clamp(_args[1], window_x.first, window_x.second);
} else {
cursor.y = clamp(_args[0], window_y.first, window_y.second);
cursor.x = clamp(_args[1], window_x.first, window_x.second);
}
}
action stbm {
/* Set Top and Bottom Margins */
/* aka scrolling region */
unsigned top = _args.size() > 0 ? _args[0] : 0;
unsigned bottom = _args.size() > 1 ? _args[1] : 0;
if (top == 0) top = 1;
if (bottom == 0) bottom = 24;
if (top < bottom && bottom <= 24) {
--top;
window = iRect(0, top, 80, bottom - top);
// also home the cursor ... depeds on DECOM.
if (_flags.DECOM) cursor = window.origin;
else cursor = iPoint(0, 0);
region_y.first = top;
region_y.second = bottom - 1;
}
}
action reset_mode {
for (auto m : _args) {
switch (m) {
case 1: if (_private) _flags.DECCKM = 0; break;
case 2: if (_private) _flags.DECANM = 0; break;
case 3: if (_private) _flags.DECCOLM = 0; break;
case 4: if (_private) _flags.DECSCLM = 0; break;
case 5: if (_private) _flags.DECSCNM = 0; break;
case 6: if (_private) {
_flags.DECOM = 0;
/* also move to new origin */
cursor = iPoint(0, 0);
}
break;
case 7: if (_private) _flags.DECAWM = 0; break;
case 8: if (_private) _flags.DECARM = 0; break;
case 9: if (_private) _flags.DECINLM = 0; break;
case 20: if (!_private) _flags.LNM = 0; break;
}
}
}
action set_mode {
for (auto m : _args) {
switch (m) {
case 1: if (_private) _flags.DECCKM = 1; break;
case 2: if (_private) _flags.DECANM = 1; break;
case 3: if (_private) _flags.DECCOLM = 1; break;
case 4: if (_private) _flags.DECSCLM = 1; break;
case 5: if (_private) _flags.DECSCNM = 1; break;
case 6: if (_private) {
_flags.DECOM = 1;
/* also move to new origin */
cursor = window.origin;
}
case 7: if (_private) _flags.DECAWM = 1; break;
case 8: if (_private) _flags.DECARM = 1; break;
case 9: if (_private) _flags.DECINLM = 1; break;
case 20: if (!_private) _flags.LNM = 1; break;
}
}
}
action tbc {
/* TBC Tabulation Clear */
for (auto arg : _args) {
switch (arg) {
case 0: if (cursor.x <= 79) _tabs[cursor.x] = 0; break;
case 3: _tabs.reset(); break;
}
}
}
action dsr {
/* Device Status Report */
for (auto arg : _args) {
switch(arg) {
default: break;
case 5: /* report status */
output->write(ESC "[0n");
break;
case 6: { /* cursor position report */
char buffer[16];
iPoint pt = cursor;
pt.x++;
pt.y++;
if (_flags.DECOM) pt.y -= region_y.first;
snprintf(buffer, sizeof(buffer)-1, ESC "[%u;%uR", pt.y, pt.x);
output->write(buffer);
break;
}
}
}
}
action erase_line {
// mode 0 and 1 erase cursor.x
iRect r(0, cursor.y, 80, 1);
for (auto arg : _args) {
switch (arg) {
case 0: {
// x ... eos
r.origin.x = cursor.x;
r.size.width = 80 - cursor.x;
screen->eraseRect(r);
break;
}
case 1: {
// 0 ... x
r.origin.x = 0;
r.size.width = cursor.x + 1;
screen->eraseRect(r);
break;
}
case 2: {
// 0 .. eos
r.origin.x = 0;
r.size.width = 80;
screen->eraseRect(r);
break;
}
}
}
}
action erase_screen {
iRect r(0, cursor.y, 80, 1);
for (auto arg : _args) {
switch (arg) {
case 0: {
// x .. eos
r.origin.x = cursor.x;
r.size.width = 80 - cursor.x;
screen->eraseRect(r);
iRect tmp(0, cursor.y + 1, 80, 24 - cursor.y - 1);
screen->eraseRect(tmp);
break;
}
case 1: {
// 0 ... x
// 0 ... x
r.origin.x = 0;
r.size.width = cursor.x + 1;
screen->eraseRect(r);
iRect tmp(0, 0, 80, cursor.y - 1);
screen->eraseRect(tmp);
break;
}
case 2: {
iRect tmp(0, 0, 80, 24);
screen->eraseRect(tmp);
break;
}
}
}
}
action vt52_erase_line {
iRect r(cursor.x, cursor.y, 80 - cursor.x, 1);
screen->eraseRect(r);
}
action vt52_erase_screen {
iRect r(cursor.x, cursor.y, 80 - cursor.x, 1);
screen->eraseRect(r);
r = iRect(0, cursor.y + 1, 80, 24 - cursor.y - 1);
screen->eraseRect(r);
}
action sgr {
/* Select Graphical Rendition */
for (auto arg : _args) {
switch(arg) {
case 0: _context.flags = Screen::FlagNormal; break;
case 1: _context.flags |= Screen::FlagBold; break;
case 4: _context.flags |= Screen::FlagUnderscore; break;
case 5: _context.flags |= Screen::FlagBlink; break;
case 7: _context.flags |= Screen::FlagInverse; break;
}
}
}
action sc {
/* Save Cursor */
_saved_context = _context;
}
# todo -- what if DECOM changes?
action rc {
_context.cursor = _saved_context.cursor;
_context.charset = _saved_context.charset;
_context.G0_charset = _saved_context.G0_charset;
_context.G1_charset = _saved_context.G1_charset;
}
control_codes = (
0x05 $answerback
| 0x07 ${ NSBeep(); }
| 0x08 ${ if (cursor.x) cursor.x--; }
| 0x09 ${ cursor.x = tab(cursor.x); }
| (0x0a | 0x0b | 0x0c) ${ if (_flags.LNM) cursor.x = 0; } $linefeed
| 0x0d ${ cursor.x = 0; }
| 0x0e ${ _context.charset = vt100_context::G1; }
| 0x0f ${ _context.charset = vt100_context::G0; }
| 0x11 ${ /* xon */ }
| 0x13 ${ /* xoff */ }
| cntrl - esc
);
args = (
';' ${ _args.push_back(0); }
| [0-9] ${ _args.back() *= 10; _args.back() += fc - '0'; }
)**
# >to(clear_args)
;
lbrace = (
'A' $cursor_up
| 'B' $cursor_down
| 'C' $cursor_right
| 'D' $cursor_left
| ('H' | 'f') $cup
| 'K' $erase_line
| 'J' $erase_screen
| 'm' $sgr
| 'r' $stbm
| 'g' $tbc
| 'h' $set_mode
| 'l' $reset_mode
| 'n' $dsr
| 'c' ${ if (_args.front() == 0) output->write(ESC "[?1;0c"); }
| 'y' ${ /* tests */ }
| 'q' ${ /* led lights */ }
| 'x' # DECREQTPARM
)
;
lparen = [AB012] ${
switch (fc) {
case 'A': _context.G0_charset = vt100_context::CharSet_A; break;
case 'B': _context.G0_charset = vt100_context::CharSet_B; break;
case '0': _context.G0_charset = vt100_context::CharSet_0; break;
case '1': _context.G0_charset = vt100_context::CharSet_1; break;
case '2': _context.G0_charset = vt100_context::CharSet_2; break;
}
};
rparen = [AB012] ${
switch (fc) {
case 'A': _context.G1_charset = vt100_context::CharSet_A; break;
case 'B': _context.G1_charset = vt100_context::CharSet_B; break;
case '0': _context.G1_charset = vt100_context::CharSet_0; break;
case '1': _context.G1_charset = vt100_context::CharSet_1; break;
case '2': _context.G1_charset = vt100_context::CharSet_2; break;
}
};
# #3 = DECDHL - Double-Height Line (top half)
# #4 = DECDHL - Double-Height Line (bottom half)
# #5 = DECSWL Single-width Line
# #6 = DECDWL Double-Width Line
pound = (
'3'
| '4'
| '5'
| '6'
| '7' # DECHCP - Hard Copy
| '8' ${
/* DECALN */
screen->fillScreen(char_info('E', 0));
}
);
dca_arg = any ${ _args.push_back((fc & 0x7f) - 32); } ;
escape_vt52 := (
'A' $cursor_up
| 'B' $cursor_down
| 'C' $cursor_right
| 'D' $cursor_left
| 'F' ${ _flags.VT52GM = 1; }
| 'G' ${ _flags.VT52GM = 0; }
| 'H' ${ cursor = window.origin; } # todo - DECOM?
| 'I' $reverse_linefeed
| 'J' $vt52_erase_screen
| 'K' $vt52_erase_line
| 'Y' ${ _args.clear(); } dca_arg dca_arg $vt52_dca
| 'Z' ${ output->write(ESC "/Z"); }
| '=' ${ _flags.DECKPAM = 1;}
| '>' ${ _flags.DECKPAM = 0; }
| '<' ${ _flags.DECANM = 1; }
)
@{ fgoto main; }
$err{ fgoto main; }
;
csi = '[' ${ _args.clear(); _args.push_back(0); _private = NO; };
private_flag = ('?' ${ _private = YES; })?;
escape := (
( control_codes | esc )**
| cancel ${ /* cancel */ fgoto main; }
| csi private_flag args lbrace
| '(' lparen
| ')' rparen
| '#' pound
| 'D' $linefeed
| 'E' ${cursor.x = 0; } $linefeed
| 'H' ${ if (cursor.x <= 79) _tabs[cursor.x] = 1; }
| 'M' $reverse_linefeed
| 'Z' ${ output->write(ESC "[?1;0c"); }
| '7' $sc
| '8' $rc
| '=' ${ _flags.DECKPAM = 1;}
| '>' ${ _flags.DECKPAM = 0; }
# | 'N'
# | 'O'
| 'c' ${ [self reset: YES]; /* should also clear the screen */ }
| '1' # DECG - graphic processor on (vt105?)
| '2' # DECG - graphic processor off (vt105?)
)
@{ fnext main; }
$err{ fgoto main; }
;
main := (
control_codes
| esc ${
if (_flags.DECANM) fgoto escape; else fgoto escape_vt52;
}
| 0x20 .. 0x7f $forward ${
screen->putc(fc, _context);
cursor.x++;
}
)**
$err{ fgoto main; }
;
write data;
}%%
@implementation VT100
+(void)load
{
[EmulatorManager registerClass: self];
}
-(id)init
{
self = [super init];
[self reset: YES];
return self;
}
+(NSString *)name
{
return @"VT100";
}
-(NSString *)name
{
return @"VT100";
}
-(const char *)termName
{
return "vt100";
}
-(BOOL)resizable
{
return NO;
}
-(struct winsize)defaultSize
{
struct winsize ws = { 24, 80, 0, 0};
return ws;
}
-(void)reset: (BOOL)hard
{
%% write init;
_args.clear();
_flags.DECANM = 1; // ansi/vt100 mode
_flags.DECARM = 0;
_flags.DECAWM = 1;
_flags.DECCKM = 0;
_flags.DECKPAM = 0;
//_flags.DECKPNM = 1;
_flags.DECCOLM = 0;
_flags.DECSCLM = 0;
_flags.DECSCNM = 0;
_flags.DECOM = 0;
_flags.DECINLM = 0;
_flags.LNM = 0;
_flags.VT52GM = 0;
if (hard) {
_context.cursor = iPoint(0,0);
_context.window = iRect(0, 0, 80, 24);
_tabs.reset();
_tabs[8] = true;
_tabs[16] = true;
_tabs[24] = true;
_tabs[32] = true;
_tabs[40] = true;
_tabs[48] = true;
_tabs[56] = true;
_tabs[64] = true;
_tabs[72] = true;
}
_context.flags = 0;
_context.charset = vt100_context::G0;
_context.G0_charset = vt100_context::CharSet_B;
_context.G1_charset = vt100_context::CharSet_B;
}
-(void)processData: (uint8_t *)data length: (size_t)length screen:(Screen *)screen output:(OutputChannel *)output
{
std::transform(data, data + length, data, [](uint8_t c){ return c & 0x7f; });
const uint8_t *eof = nullptr;
const uint8_t *p = data;
const uint8_t *pe = std::copy_if(data, data + length, data, [](uint8_t c){
if (c == 0 || c == 0x7f) return false;
return true;
});
if (p == pe) return;
iPoint &cursor = _context.cursor;
iRect &window = _context.window;
std::pair<unsigned, unsigned> window_x(0u, 80-1);
std::pair<unsigned, unsigned> window_y(0u, 24-1);
std::pair<unsigned, unsigned> region_y(window.minY(), window.maxY()-1);
auto cursor_in_region = [&](){
return cursor.y >= region_y.first && cursor.y <= region_y.second;
};
/* todo - vt100 rom sometimes tabs to 80, sometimes doesn't. */
/* difference being: tab, x < x wraps to next line? */
auto tab = [&](unsigned x) -> unsigned {
if (x >= 79) return x;
for (x = x + 1; x < 80; ++x) {
if (_tabs[x]) return x;
}
return 79; //?
};
%%write exec;
if (cursor.x == 80) screen->setCursor(iPoint(79, cursor.y));
else screen->setCursor(cursor);
}
static const char *RemapKey(unichar uc, NSEventModifierFlags flags, struct __vt100flags vt100flags)
{
auto DECKPAM = vt100flags.DECKPAM;
/*
DECKPAM Keypad Application Mode (DEC Private)
The auxiliary keypad keys will transmit control sequences as defined in Tables 3-7 and 3-8.
*/
auto DECCKM = vt100flags.DECCKM;
/*
DECCKM Cursor Keys Mode (DEC Private)
This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. This mode is only effective when the terminal is in keypad application mode (see DECKPAM) and the ANSI/VT52 mode (DECANM) is set (see DECANM). Under these conditions, if the cursor key mode is reset, the four cursor function keys will send ANSI cursor control commands. If cursor key mode is set, the four cursor function keys will send application functions.
*/
auto LNM = vt100flags.LNM;
auto DECANM = vt100flags.DECANM;
/*
DECANM ANSI/VT52 Mode (DEC Private)
This is a private parameter applicable to set mode (SM) and reset mode (RM) control sequences. The reset state causes only VT52 compatible escape sequences to be interpreted and executed. The set state causes only ANSI "compatible" escape and control sequences to be interpreted and executed.
*/
#if 0
/* Device-independent bits found in event modifier flags */
typedef NS_OPTIONS(NSUInteger, NSEventModifierFlags) {
NSEventModifierFlagCapsLock = 1 << 16, // Set if Caps Lock key is pressed.
NSEventModifierFlagShift = 1 << 17, // Set if Shift key is pressed.
NSEventModifierFlagControl = 1 << 18, // Set if Control key is pressed.
NSEventModifierFlagOption = 1 << 19, // Set if Option or Alternate key is pressed.
NSEventModifierFlagCommand = 1 << 20, // Set if Command key is pressed.
NSEventModifierFlagNumericPad = 1 << 21, // Set if any key in the numeric keypad is pressed.
NSEventModifierFlagHelp = 1 << 22, // Set if the Help key is pressed.
NSEventModifierFlagFunction = 1 << 23, // Set if any function key is pressed.
// Used to retrieve only the device-independent modifier flags, allowing applications to mask off the device-dependent modifier flags, including event coalescing information.
NSEventModifierFlagDeviceIndependentFlagsMask = 0xffff0000UL
};
#endif
/*
NSEnterCharacter: keypad Enter Key
NSNewlineCharacter: \n
NSCarriageReturnCharacter: \r (main Enter/Return key)
*/
//NSLog(@"%c %02x %08lx", isprint(uc) ? uc : '.', uc, (unsigned long)flags);
if (DECKPAM && (flags & NSNumericPadKeyMask)) {
switch (uc) {
case '0': return DECANM ? ESC "Op" : ESC "?p";
case '1': return DECANM ? ESC "Oq" : ESC "?q";
case '2': return DECANM ? ESC "Or" : ESC "?r";
case '3': return DECANM ? ESC "Os" : ESC "?s";
case '4': return DECANM ? ESC "Ot" : ESC "?t";
case '5': return DECANM ? ESC "Ou" : ESC "?u";
case '6': return DECANM ? ESC "Ov" : ESC "?v";
case '7': return DECANM ? ESC "Ow" : ESC "?w";
case '8': return DECANM ? ESC "Ox" : ESC "?x";
case '9': return DECANM ? ESC "Oy" : ESC "?y";
case ',': return DECANM ? ESC "Ol" : ESC "?l";
case '-': return DECANM ? ESC "Om" : ESC "?m";
case '.': return DECANM ? ESC "On" : ESC "?n";
case NSEnterCharacter: return DECANM ? ESC "OM" : ESC "?M";
}
}
switch(uc) {
case NSUpArrowFunctionKey:
if (DECANM) return DECKPAM ? ESC "OA" : ESC "[A";
return ESC "A";
case NSDownArrowFunctionKey:
if (DECANM) return DECKPAM ? ESC "OB" : ESC "[B";
return ESC "B";
case NSRightArrowFunctionKey:
if (DECANM) return DECKPAM ? ESC "OC" : ESC "[C";
return ESC "C";
case NSLeftArrowFunctionKey:
if (DECANM) return DECKPAM ? ESC "OD" : ESC "[D";
return ESC "D";
case NSF1FunctionKey: return DECANM ? ESC "OP" : ESC "P";
case NSF2FunctionKey: return DECANM ? ESC "OQ" : ESC "Q";
case NSF3FunctionKey: return DECANM ? ESC "OR" : ESC "R";
case NSF4FunctionKey: return DECANM ? ESC "OS" : ESC "S";
/* return/enter key is CR */
case NSEnterCharacter: case NSNewlineCharacter: case NSCarriageReturnCharacter:
return LNM ? "\n\r" : "\r";
// NSDeleteCharacter IS 0x7f.
//case NSDeleteCharacter: return "\x7f"; //
}
return nullptr;
}
-(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output
{
NSEventModifierFlags flags = [event modifierFlags];
NSString *chars = [event charactersIgnoringModifiers];
NSUInteger length = [chars length];
for (unsigned i = 0; i < length; ++i) {
unichar uc = [chars characterAtIndex: i];
const char *str = RemapKey(uc, flags, _flags);
if (str) {
output->write(str);
} else if (uc <= 0x7f) {
uint8_t c = uc;
if (flags & NSControlKeyMask) c = CTRL(c);
output->write(c);
}
}
}
@end

33
Emulators/VT50.h Normal file
View File

@ -0,0 +1,33 @@
//
// VT50.h
// TwoTerm
//
// Created by Kelvin Sherlock on 3/2/2018.
//
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "Emulator.h"
#include "iGeometry.h"
#include "Screen.h"
@interface VT50x : NSObject <Emulator> {
unsigned cs;
int _scratch[2];
context _context;
unsigned _model;
BOOL _altKeyPad;
BOOL _graphics;
}
@end
@interface VT50 : VT50x
@end
@interface VT50H : VT50x
@end

447
Emulators/VT50.mm.ragel Normal file
View File

@ -0,0 +1,447 @@
//
// VT50.m
// TwoTerm
//
// Created by Kelvin Sherlock on 3/2/2018.
//
#include <sys/ttydefaults.h>
#include <cctype>
#include <cstdio>
#include <numeric>
#include <algorithm>
#import "VT50.h"
#include "OutputChannel.h"
#include "Screen.h"
#define ESC "\x1b"
enum {
ModelVT50,
ModelVT50H,
ModelVT52,
ModelVT55
};
namespace {
void normalize(iRect &r){
r.origin.y <<= 1;
r.size.height <<= 1;
}
void normalize(iPoint &p) {
p.y <<= 1;
}
}
%%{
machine vt50;
alphtype unsigned int;
esc = 0x1b;
action vt50h { _model == ModelVT50H }
action vt50 { _model == ModelVT50 }
action tab {
if (cursor.x < 72) cursor.x = (cursor.x + 8) & ~7;
else if (cursor.x < window.maxX() -1) cursor.x++;
}
action linefeed {
if (cursor.y < window.maxY() - 1) cursor.y++;
else {
screen->scrollUp();
screen->scrollUp();
}
}
action rlinefeed {
// this is documented as being vt52++
// however the 2BSD termcap entry (dating to 1980)
// and every termcap since claims 50h supports it...
if (cursor.y) cursor.y--;
else {
screen->scrollDown();
screen->scrollDown();
}
}
action erase_eos {
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize( window.maxX() - cursor.x, 1);
normalize(tmp);
screen->eraseRect(tmp);
tmp.origin = iPoint(0, cursor.y+1);
tmp.size = iSize(window.maxX(), window.maxY() - cursor.y - 1);
normalize(tmp);
screen->eraseRect(tmp);
}
action erase_eol {
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize( window.maxX() - cursor.x, 1);
normalize(tmp);
screen->eraseRect(tmp);
}
action identify {
// NB -- these indicate no copier.
switch(_model) {
case ModelVT50:
output->write(ESC "/A");
break;
case ModelVT50H:
output->write(ESC "/H");
break;
}
}
action dca {
unsigned y = _scratch[0];
if (y >= window.maxY()) y = window.maxY() -1;
cursor.y = y;
unsigned x = _scratch[1];
if (x >= window.maxX()) x = window.maxX() -1;
cursor.x = x;
}
action forward {
if (cursor.x > window.maxX()-1) {
cursor.x = window.minX();
if (cursor.y >= window.maxY()-1) {
screen->scrollUp();
screen->scrollUp();
} else {
cursor.y++;
}
}
}
arg1 = any ${ _scratch[0] = ((fc & 0x7f) - 32); };
arg2 = any ${ _scratch[1] = ((fc & 0x7f) - 32); };
control_codes = (
0x07 ${ NSBeep(); }
| 0x08 ${ if (cursor.x) cursor.x--; }
| 0x09 $tab
| 0x0a $linefeed
| 0x0d ${ cursor.x = 0; }
| 0x0e when vt50h arg1 arg2 $dca
| cntrl - esc
);
escape_codes = control_codes* <: (
esc
| 'A' ${ if (cursor.y) cursor.y--; }
| 'B' when vt50h ${ if (cursor.y < window.maxY() -1) cursor.y++; }
| 'C' ${ if (cursor.x < window.maxX() -1) cursor.x++; }
| 'D' when vt50h ${ if (cursor.x) cursor.x--; }
#| 'F' when vt52_or_better ${ _graphics = true; }
#| 'G' when vt52_or_better ${ _graphics = false; }
| 'H' ${ cursor = iPoint(0, 0); }
| 'I' when vt50h $rlinefeed
| 'J' $erase_eos
| 'K' $erase_eol
| 'Y' when vt50h arg1 arg2 $dca
| 'Z' $identify
#| '=' when vt52_or_better ${ _altKeyPad = true; }
#| '>' when vt52_or_better ${ _altKeyPad = false; }
| any
);
main := (
control_codes
| esc escape_codes
| 0x20 .. 0x7e $forward ${
uint8_t c = fc;
if (c & 0x40) c &= ~0x20;
screen->putc(c, iPoint(cursor.x, cursor.y << 1), 0);
cursor.x++;
}
| any
)** $err { fgoto main; };
write data;
}%%
@implementation VT50x
-(BOOL)resizable
{
return NO;
}
-(struct winsize)defaultSize
{
struct winsize ws = { 0, 0, 0, 0};
// VT50x have 12 rows. They are double spaced.
ws.ws_row = 12;
ws.ws_col = 80;
return ws;
}
-(struct winsize)displaySize
{
struct winsize ws = { 0, 0, 0, 0};
// VT50x have 12 rows. They are double spaced.
ws.ws_row = 24;
ws.ws_col = 80;
return ws;
}
+(NSString *)name {
return @"";
}
-(NSString *)name {
return @"";
}
-(const char *)termName {
return "";
}
-(void)reset: (BOOL)hard
{
%% write init;
_altKeyPad = false;
_graphics = false;
if (hard) {
_context.cursor = iPoint(0,0);
_context.window = iRect(0, 0, 80, 12);
}
_context.flags = 0;
}
-(void)keyDown: (NSEvent *)event screen: (Screen *)screen output: (OutputChannel *)output
{
NSEventModifierFlags flags = [event modifierFlags];
NSString *chars = [event charactersIgnoringModifiers];
NSUInteger length = [chars length];
for (unsigned i = 0; i < length; ++i)
{
unichar uc = [chars characterAtIndex: i];
uint8_t c;
if (flags & NSNumericPadKeyMask)
{
if (_altKeyPad)
{
const char *str = NULL;
switch (uc)
{
case '0':
str = ESC "?p";
break;
case '1':
str = ESC "?q";
break;
case '2':
str = ESC "?r";
break;
case '3':
str = ESC "?s";
break;
case '4':
str = ESC "?t";
break;
case '5':
str = ESC "?u";
break;
case '6':
str = ESC "?v";
break;
case '7':
str = ESC "?w";
break;
case '8':
str = ESC "?x";
break;
case '9':
str = ESC "?y";
break;
case '.':
str = ESC "?n";
break;
case NSNewlineCharacter: //?
case NSEnterCharacter:
str = ESC "?M";
break;
}
if (str)
{
output->write(str);
break;
}
}
}
switch (uc)
{
case NSEnterCharacter:
output->write('\r');
break;
case NSDeleteCharacter:
output->write(0x7f);
break;
case NSUpArrowFunctionKey:
output->write(ESC "A");
break;
case NSDownArrowFunctionKey:
output->write(ESC "B");
break;
case NSRightArrowFunctionKey:
output->write(ESC "C");
break;
case NSLeftArrowFunctionKey:
output->write(ESC "D");
break;
// 3 function keys. (VT50H / VT52)
case NSF1FunctionKey:
output->write(ESC "P");
break;
case NSF2FunctionKey:
output->write(ESC "Q");
break;
case NSF3FunctionKey:
output->write(ESC "R");
break;
default:
if (uc > 0x7f) break;
c = uc;
if (flags & (NSShiftKeyMask | NSAlphaShiftKeyMask))
{
c = toupper(c);
}
if (flags & NSControlKeyMask)
{
c = CTRL(c);
}
output->write(c);
break;
}
}
}
-(void)processData: (uint8_t *)data length: (size_t)length screen:(Screen *)screen output:(OutputChannel *)output
{
std::transform(data, data + length, data, [](uint8_t c){ return c & 0x7f; });
const uint8_t *eof = nullptr;
const uint8_t *p = data;
const uint8_t *pe = std::copy_if(data, data + length, data, [](uint8_t c){
if (c == 0 || c == 0x7f) return false;
return true;
});
iPoint &cursor = _context.cursor;
const iRect &window = _context.window;
%%write exec;
auto cc = cursor;
cc.y <<= 1;
if (cc.x == 80) cc.x = 79;
screen->setCursor(cc);
}
@end
@implementation VT50
+(void)load {
[EmulatorManager registerClass: self];
}
+(NSString *)name {
return @"VT50";
}
-(NSString *)name {
return @"VT50";
}
-(const char *)termName {
return "vt50";
}
-(id)init {
if ((self = [super init])) {
_model = ModelVT50;
[self reset: YES];
}
return self;
}
@end
@implementation VT50H
+(void)load {
[EmulatorManager registerClass: self];
}
+(NSString *)name {
return @"VT50H";
}
-(NSString *)name {
return @"VT50H";
}
-(const char *)termName {
return "vt50h";
}
-(id)init {
if ((self = [super init])) {
_model = ModelVT50H;
[self reset: YES];
}
return self;
}
@end

View File

@ -28,11 +28,14 @@
@interface VT52 : VT5x
@end
/*
@interface VT50H : VT5x
@end
@interface VT50 : VT5x
@end
*/
@interface VT55 : VT5x
@end

View File

@ -43,7 +43,7 @@ enum {
#if 0
@implementation VT50
+(void)load {
@ -72,7 +72,7 @@ enum {
-(id)init {
if ((self = [super init])) {
_model = ModelVT50;
[self reset];
[self reset: YES];
}
return self;
@ -104,7 +104,7 @@ enum {
-(id)init {
if ((self = [super init])) {
_model = ModelVT50H;
[self reset];
[self reset: YES];
}
return self;
@ -119,6 +119,8 @@ enum {
@end
#endif
@implementation VT52
+(void)load {
@ -141,7 +143,7 @@ enum {
-(id)init {
if ((self = [super init])) {
_model = ModelVT52;
[self reset];
[self reset: YES];
}
return self;
}
@ -168,7 +170,7 @@ enum {
-(id)init {
if ((self = [super init])) {
_model = ModelVT55;
[self reset];
[self reset: YES];
}
return self;
@ -319,15 +321,18 @@ enum {
}
}
-(void)reset
-(void)reset: (BOOL)hard
{
cs = StateText;
_escape = false;
_altKeyPad = false;
_graphics = false;
_context.cursor = iPoint(0,0);
_context.window = iRect(0, 0, 80, 24);
if (_model <= ModelVT50H) _context.window = iRect(0, 0, 80, 12);
if (hard) {
_context.cursor = iPoint(0,0);
_context.window = iRect(0, 0, 80, 24);
if (_model <= ModelVT50H) _context.window = iRect(0, 0, 80, 12);
}
_context.flags = 0;
}

View File

@ -1,284 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
<capability name="box content view" minToolsVersion="7.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NewTerminalWindowController">
<connections>
<outlet property="backgroundColorControl" destination="53" id="65"/>
<outlet property="bloomSlider" destination="MVc-mQ-qGn" id="TzC-h7-eSd"/>
<outlet property="blurSlider" destination="78" id="100"/>
<outlet property="colorSchemeButton" destination="68" id="92"/>
<outlet property="darkenSlider" destination="84" id="99"/>
<outlet property="effectsButton" destination="62" id="93"/>
<outlet property="exampleView" destination="123" id="129"/>
<outlet property="foregroundColorControl" destination="49" id="64"/>
<outlet property="lightenSlider" destination="82" id="101"/>
<outlet property="terminalTypeButton" destination="55" id="67"/>
<outlet property="vignetteSlider" destination="vAv-z0-AKd" id="tmI-Tz-29w"/>
<outlet property="window" destination="1" id="38"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="New Terminal" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="1">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" texturedBackground="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="232" width="400" height="613"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
<view key="contentView" wantsLayer="YES" misplaced="YES" id="2">
<rect key="frame" x="0.0" y="0.0" width="400" height="613"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField verticalHuggingPriority="750" id="9">
<rect key="frame" x="17" y="573" width="99" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Terminal Type:" id="10">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" id="17">
<rect key="frame" x="262" y="18" width="118" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="roundTextured" title="Connect" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="18">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="connectButton:" target="-2" id="41"/>
</connections>
</button>
<button verticalHuggingPriority="750" id="19">
<rect key="frame" x="20" y="18" width="118" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="roundTextured" title="Cancel" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="20">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="cancelButton:" target="-2" id="40"/>
</connections>
</button>
<popUpButton verticalHuggingPriority="750" id="55">
<rect key="frame" x="121" y="568" width="259" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="roundTextured" title="Item 1" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" selectedItem="58" id="56">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" title="OtherViews" id="57">
<items>
<menuItem title="Item 1" state="on" id="58"/>
<menuItem title="Item 2" id="59"/>
<menuItem title="Item 3" id="60"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<box autoresizesSubviews="NO" borderType="line" title="Colors" id="76">
<rect key="frame" x="17" y="441" width="366" height="124"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<view key="contentView" id="xsD-uS-uc3">
<rect key="frame" x="1" y="1" width="364" height="108"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" id="50">
<rect key="frame" x="15" y="48" width="83" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Foreground:" id="51">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" id="90">
<rect key="frame" x="15" y="79" width="83" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Scheme:" id="91">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" id="52">
<rect key="frame" x="15" y="17" width="83" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Background:" id="54">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<colorWell id="49">
<rect key="frame" x="103" y="45" width="44" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="color" red="0.0" green="1" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="128"/>
</connections>
</colorWell>
<colorWell id="53">
<rect key="frame" x="103" y="14" width="44" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="color" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="127"/>
</connections>
</colorWell>
<popUpButton verticalHuggingPriority="750" id="68">
<rect key="frame" x="103" y="74" width="243" height="25"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="roundTextured" title="Item 1" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" selectedItem="71" id="69">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" title="OtherViews" id="70">
<items>
<menuItem title="Item 1" state="on" id="71"/>
<menuItem title="Item 2" id="72"/>
<menuItem title="Item 3" id="73"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="setColorScheme:" target="-2" id="122"/>
</connections>
</popUpButton>
</subviews>
</view>
</box>
<box autoresizesSubviews="NO" misplaced="YES" borderType="line" title="Effects" id="77">
<rect key="frame" x="17" y="238" width="366" height="199"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<view key="contentView" id="Pmg-yY-Yvg">
<rect key="frame" x="1" y="1" width="364" height="183"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<slider verticalHuggingPriority="750" misplaced="YES" id="78">
<rect key="frame" x="85" y="131" width="263" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" tickMarkPosition="above" sliderType="linear" id="79"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="124"/>
<binding destination="-2" name="enabled" keyPath="effectsEnabled" id="115"/>
</connections>
</slider>
<slider verticalHuggingPriority="750" misplaced="YES" id="82">
<rect key="frame" x="85" y="79" width="263" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" doubleValue="0.25" tickMarkPosition="above" sliderType="linear" id="83"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="125"/>
<binding destination="-2" name="enabled" keyPath="effectsEnabled" id="117"/>
</connections>
</slider>
<textField verticalHuggingPriority="750" misplaced="YES" id="80">
<rect key="frame" x="25" y="134" width="56" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Blur:" id="81">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" misplaced="YES" id="86">
<rect key="frame" x="17" y="84" width="64" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Backlight:" id="87">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" misplaced="YES" id="88">
<rect key="frame" x="15" y="59" width="66" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Scanlines:" id="89">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<slider verticalHuggingPriority="750" misplaced="YES" id="84">
<rect key="frame" x="85" y="56" width="263" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" doubleValue="0.5" tickMarkPosition="above" sliderType="linear" id="85"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="126"/>
<binding destination="-2" name="enabled" keyPath="effectsEnabled" id="119"/>
</connections>
</slider>
<slider verticalHuggingPriority="750" misplaced="YES" id="vAv-z0-AKd">
<rect key="frame" x="85" y="31" width="263" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" doubleValue="1" tickMarkPosition="above" sliderType="linear" id="6ek-4n-F91"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="xT7-DI-d9v"/>
<binding destination="-2" name="enabled" keyPath="effectsEnabled" id="Zom-p6-sns"/>
</connections>
</slider>
<button misplaced="YES" id="62">
<rect key="frame" x="83" y="157" width="118" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Effects Enabled" bezelStyle="regularSquare" imagePosition="left" alignment="left" state="on" inset="2" id="63">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="-2" name="value" keyPath="effectsEnabled" id="107"/>
</connections>
</button>
<textField verticalHuggingPriority="750" misplaced="YES" id="p8Y-GX-qsU">
<rect key="frame" x="33" y="109" width="46" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Bloom:" id="JPr-iB-JMl">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<slider verticalHuggingPriority="750" misplaced="YES" id="MVc-mQ-qGn">
<rect key="frame" x="83" y="106" width="263" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" doubleValue="0.75" tickMarkPosition="above" sliderType="linear" id="rry-su-ojc"/>
<connections>
<action selector="filterParameterChanged:" target="-2" id="QKT-s7-pAK"/>
<binding destination="-2" name="enabled" keyPath="effectsEnabled" id="DfY-jU-vle"/>
</connections>
</slider>
<textField verticalHuggingPriority="750" misplaced="YES" id="7Qa-e5-7OW">
<rect key="frame" x="20" y="33" width="59" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Vignette:" id="x41-sA-EDR">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
</box>
<customView id="123" customClass="ExampleView">
<rect key="frame" x="20" y="50" width="360" height="145"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
</customView>
</subviews>
</view>
<contentBorderThickness minY="0.0" maxY="0.0"/>
<connections>
<outlet property="delegate" destination="-2" id="39"/>
</connections>
<point key="canvasLocation" x="116" y="220.5"/>
</window>
<userDefaultsController representsSharedInstance="YES" id="102"/>
</objects>
</document>

View File

@ -6,8 +6,6 @@
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
@ -17,11 +15,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>1.0r6</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2</string>
<string>6</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>

View File

@ -19,18 +19,6 @@
NSColorWell *_foregroundColorControl;
NSColorWell *_backgroundColorControl;
NSButton *_effectsButton;
NSSlider *_blurSlider;
NSSlider *_lightenSlider;
NSSlider *_darkenSlider;
ExampleView *_exampleView;
BOOL _effectsEnabled;
}
@property (nonatomic, assign) IBOutlet ExampleView *exampleView;
@ -42,15 +30,6 @@
@property (nonatomic, assign) IBOutlet NSColorWell *foregroundColorControl;
@property (nonatomic, assign) IBOutlet NSColorWell *backgroundColorControl;
@property (nonatomic, assign) IBOutlet NSButton *effectsButton;
@property (nonatomic, assign) IBOutlet NSSlider *blurSlider;
@property (nonatomic, assign) IBOutlet NSSlider *lightenSlider;
@property (nonatomic, assign) IBOutlet NSSlider *darkenSlider;
@property (nonatomic, assign) IBOutlet NSSlider *bloomSlider;
@property (nonatomic, assign) IBOutlet NSSlider *vignetteSlider;
@property (nonatomic, assign) BOOL effectsEnabled;
-(IBAction)cancelButton: (id)sender;
@ -59,10 +38,7 @@
-(IBAction)colorChanged: (id)sender;
-(IBAction)setColorScheme: (id)sender;
-(IBAction)filterParameterChanged: (id)sender;
-(NSMenu *)colorMenu;
-(NSColor *)recalcBackground;
@end

View File

@ -18,16 +18,9 @@
@synthesize terminalTypeButton = _terminalTypeButton;
@synthesize colorSchemeButton = _colorSchemeButton;
@synthesize effectsButton = _effectsButton;
@synthesize foregroundColorControl = _foregroundColorControl;
@synthesize backgroundColorControl = _backgroundColorControl;
@synthesize blurSlider = _blurSlider;
@synthesize lightenSlider = _lightenSlider;
@synthesize darkenSlider = _darkenSlider;
@synthesize effectsEnabled = _effectsEnabled;
// colors
enum {
kCustom = 0,
@ -59,12 +52,11 @@ enum {
[super windowDidLoad];
window = [self window];
//[[window contentView] setWantsLayer: YES];
//[window setAutorecalculatesContentBorderThickness: NO forEdge: NSMinYEdge];
//[window setAutorecalculatesContentBorderThickness: NO forEdge: NSMaxYEdge];
[self setEffectsEnabled: YES];
[_terminalTypeButton setMenu: [EmulatorManager emulatorMenu]];
@ -143,16 +135,11 @@ enum {
[userInfo setObject: klass forKey: kClass];
[userInfo setObject: [_foregroundColorControl color] forKey: kForegroundColor];
[userInfo setObject: [self recalcBackground] forKey: kBackgroundColor];
if (_effectsEnabled)
{
[userInfo setObject: [_exampleView contentFilters] forKey: kContentFilters];
}
[userInfo setObject: [_backgroundColorControl color] forKey: kBackgroundColor];
[nc postNotificationName: kNotificationNewTerminal object: self userInfo: userInfo];
// post notificiation...
}
@ -205,43 +192,9 @@ enum {
}
[self filterParameterChanged: nil];
}
-(IBAction)filterParameterChanged: (id)sender
{
[_exampleView setForegroundColor: [_foregroundColorControl color]];
[_exampleView setColor: [self recalcBackground]];
if (_effectsEnabled)
{
[_exampleView setBlur: [_blurSlider floatValue]];
//[_exampleView setLighten: [_lightenSlider floatValue]];
[_exampleView setDarken: [_darkenSlider floatValue]];
[_exampleView setBloom: [_bloomSlider floatValue]];
[_exampleView setVignette: [_vignetteSlider floatValue]];
}
else
{
[_exampleView setBlur: 0.0];
//[_exampleView setLighten: 0.0];
[_exampleView setDarken: 0.0];
[_exampleView setBloom: 0.0];
[_exampleView setVignette: 0.0];
}
[_exampleView updateEffects];
[_exampleView setNeedsDisplay: YES];
}
-(void)setEffectsEnabled:(BOOL)effectsEnabled
{
_effectsEnabled = effectsEnabled;
[self filterParameterChanged: nil];
}
#pragma mark -
#pragma mark NSWindowDelegate
@ -254,17 +207,6 @@ enum {
[self autorelease];
}
-(NSColor *)recalcBackground {
NSColor *bg = [_backgroundColorControl color];
NSColor *fg = [_foregroundColorControl color];
CGFloat value = [_lightenSlider doubleValue];
if (_effectsEnabled) {
bg = [bg blendedColorWithFraction: value ofColor: fg];
}
return bg;
}
@end

View File

@ -14,30 +14,68 @@
@protocol Emulator;
@interface TermWindowController : NSWindowController <NSWindowDelegate> {
NSDictionary *_parameters;
EmulatorView *_emulatorView;
ColorView *_colorView;
@interface TermWindowController : NSWindowController <NSWindowDelegate, NSPopoverDelegate> {
IBOutlet EmulatorView *_emulatorView;
IBOutlet ColorView *_colorView;
NSObject <Emulator> *_emulator;
NSThread * _thread;
int _fd;
std::atomic<pid_t> _pid;
/* popover configuration options */
IBOutlet NSColorWell *_fg;
IBOutlet NSColorWell *_bg;
IBOutlet NSButton *_effectsButton;
IBOutlet NSSlider *_blurSlider;
IBOutlet NSSlider *_lightenSlider;
IBOutlet NSSlider *_darkenSlider;
IBOutlet NSSlider *_bloomSlider;
IBOutlet NSSlider *_vignetteSlider;
}
@property (nonatomic, retain) NSDictionary *parameters;
@property (nonatomic, retain) IBOutlet NSViewController *popoverViewController;
@property (nonatomic, retain) IBOutlet NSPopover *popover;
@property (nonatomic, retain) IBOutlet EmulatorView *emulatorView;
@property (nonatomic, retain) IBOutlet ColorView *colorView;
@property (nonatomic, retain) NSObject<Emulator> *emulator;
@property (nonatomic, assign) BOOL effectsEnabled;
@property (nonatomic, assign) double blurValue;
@property (nonatomic, assign) double bloomValue;
@property (nonatomic, assign) double backlightValue;
@property (nonatomic, assign) double scanlineValue;
@property (nonatomic, assign) double vignetteValue;
@property (nonatomic, retain) NSColor *foregroundColor;
@property (nonatomic, retain) NSColor *backgroundColor;
-(void)initPTY;
-(void)childFinished: (int)status;
-(void)processData: (const void *)buffer size: (size_t)size;
-(void)setParameters: (NSDictionary *)parameters;
-(IBAction)resetTerminal: (id)sender;
-(IBAction)hardResetTerminal: (id)sender;
@end
@interface TermWindowController (Config)
- (IBAction)configure: (id)sender;
- (IBAction)foregroundColor:(id)sender;
- (IBAction)backgroundColor:(id)sender;
- (IBAction)swapColors:(id)sender;
- (IBAction)filterParameterChanged: (id)sender;
-(void) updateBackgroundColor;
-(void) updateForegroundColor;
-(NSArray *)effectsFilter;
@end

View File

@ -6,6 +6,9 @@
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import <CoreImage/CoreImage.h>
#import "ScanLineFilter.h"
#import "TermWindowController.h"
#import "EmulatorView.h"
#import "CurveView.h"
@ -15,7 +18,7 @@
#include <sys/event.h>
#include <sys/time.h>
#include <atomic>
#include <utility>
#import "Defaults.h"
@ -31,13 +34,12 @@
#include <string>
#include <vector>
#include "ChildMonitor.h"
#include "ColorView.h"
@implementation TermWindowController
@synthesize emulator = _emulator;
@synthesize emulatorView = _emulatorView;
@synthesize colorView = _colorView;
@synthesize parameters = _parameters;
+(id)new
{
@ -46,36 +48,94 @@
-(void)dealloc
{
[_emulator release];
[_emulatorView release];
[_colorView release];
[_parameters release];
[_thread release];
[[ChildMonitor monitor] removeController: self];
[_emulator release];
[_popover release];
[_popoverViewController release];
[_foregroundColor release];
[_backgroundColor release];
[super dealloc];
}
/*
-(void)awakeFromNib
{
[self initPTY];
-(id)initWithWindow:(NSWindow *)window {
if ((self = [super initWithWindow: window])) {
_foregroundColor = [[NSColor greenColor] retain];
_backgroundColor = [[NSColor blackColor] retain];
_bloomValue = 0.75;
_blurValue = 0.0;
_backlightValue = 0.25;
_scanlineValue = 0.5;
_vignetteValue = 0.5;
_effectsEnabled = YES;
}
return self;
}
*/
-(void)setParameters: (NSDictionary *)parameters {
NSColor *o;
Class klass;
o = [parameters objectForKey: kForegroundColor];
o = o ? (NSColor *)o : [NSColor greenColor];
[self setForegroundColor: o];
o = [parameters objectForKey: kBackgroundColor];
o = o ? (NSColor *)o : [NSColor blackColor];
[self setBackgroundColor: o];
klass = [parameters objectForKey: kClass];
if (!klass || ![klass conformsToProtocol: @protocol(Emulator)])
{
klass = Nil;
//klass = [VT52 class];
}
[self willChangeValueForKey: @"emulator"];
_emulator = [klass new];
[self didChangeValueForKey: @"emulator"];
#if 0
[self updateBackgroundColor];
[self updateForegroundColor];
#endif
}
-(void)initPTY
{
static std::string username;
static std::string terminfo;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// getlogin() sometimes returns crap.
username = [NSUserName() UTF8String];
char *cp = getenv("TERMINFO_DIRS");
if (cp && *cp) {
terminfo = cp;
terminfo.push_back(':');
}
NSString *s = [[NSBundle mainBundle] resourcePath];
s = [s stringByAppendingPathComponent: @"terminfo"];
terminfo += [s UTF8String];
});
pid_t pid;
int fd;
struct termios term;
struct winsize ws = [_emulator defaultSize];
memset(&term, 0, sizeof(term));
//term.c_oflag = OPOST | ONLCR;
//term.c_lflag = ECHO;
//term.c_iflag = ICRNL; // | ICANON | ECHOE | ISIG;
term.c_oflag = TTYDEF_OFLAG;
term.c_lflag = TTYDEF_LFLAG;
term.c_iflag = TTYDEF_IFLAG;
@ -89,21 +149,16 @@
[_emulator initTerm: &term];
// getlogin() sometimes returns crap.
if (username.empty()) {
username = [NSUserName() UTF8String];
}
//NSLog(@"%@ %s %s", NSUserName(), getlogin(), getpwent()->pw_name);
_pid = forkpty(&_fd, NULL, &term, &ws);
pid = forkpty(&fd, NULL, &term, &ws);
if (_pid < 0)
if (pid < 0)
{
fprintf(stderr, "forkpty failed\n");
fflush(stderr);
return;
}
if (_pid == 0)
if (pid == 0)
{
std::vector<const char *> environ;
@ -118,8 +173,12 @@
s.append("TERM=");
s.append([_emulator termName]);
s.append(1, (char)0);
s.append("TERMINFO_DIRS=");
s.append(terminfo.c_str());
s.append(1, (char)0);
s.append(1, (char)0);
for (std::string::size_type index = 0;;)
@ -175,199 +234,240 @@
[window setMinSize: [window frame].size];
[_emulatorView setFd: _fd];
[self monitor];
[_emulatorView setFd: fd];
[[ChildMonitor monitor] addController: self pid: pid fd: fd];
}
-(BOOL)read: (int)fd {
BOOL rv = NO;
for(;;) {
uint8_t buffer[1024];
ssize_t size = read(fd, buffer, sizeof(buffer));
if (size < 0 && errno == EINTR) continue;
if (size <= 0) break;
[_emulatorView processData: buffer size: size];
rv = YES;
}
return rv;
-(void)childFinished: (int)status {
[_emulatorView childFinished: status];
}
-(int)wait: (pid_t)pid {
std::atomic_exchange(&_pid, -1);
int status = 0;
for(;;) {
int ok = waitpid(pid, &status, WNOHANG);
if (ok >= 0) break;
if (errno == EINTR) continue;
NSLog(@"waitpid(%d): %s", pid, strerror(errno));
break;
}
return status;
-(void)processData: (const void *)buffer size: (size_t)size {
[_emulatorView processData: (uint8_t *)buffer size: size];
}
-(void)monitor {
int fd = _fd;
pid_t pid = _pid;
int q = kqueue();
struct kevent events[2] = {};
EV_SET(&events[0], pid, EVFILT_PROC, EV_ADD | EV_RECEIPT, NOTE_EXIT | NOTE_EXITSTATUS, 0, NULL);
EV_SET(&events[1], fd, EVFILT_READ, EV_ADD | EV_RECEIPT, 0, 0, NULL);
int flags;
// non-blocking io.
if (fcntl(_fd, F_GETFL, &flags) < 0) flags = 0;
fcntl(_fd, F_SETFL, flags | O_NONBLOCK);
kevent(q, events, 2, NULL, 0, NULL);
[_emulatorView childBegan];
_thread = [[NSThread alloc] initWithBlock: ^(){
struct kevent events[2] = {};
bool stop = false;
int status = 0;
while (!stop) {
int n = kevent(q, NULL, 0, events, 2, NULL);
if (n <= 0) {
NSLog(@"kevent");
break;
}
for (unsigned i = 0; i < n; ++i) {
const auto &e = events[i];
unsigned flags = e.flags;
if (e.filter == EVFILT_READ) {
int fd = (int)e.ident;
if (flags & EV_EOF) {
NSLog(@"EV_EOF");
}
if (flags & EV_ERROR) {
NSLog(@"EV_ERROR");
}
[self read: fd];
continue;
}
if (e.filter == EVFILT_PROC) {
pid_t pid = (pid_t)e.ident;
NSLog(@"Child finished");
status = [self wait: pid];
stop = true;
}
}
}
if (![_thread isCancelled]) {
// read any lingering io...
[self read: fd];
[_emulatorView childFinished: status];
}
close(q);
close(fd);
_fd = -1;
//NSLog(@"Closing fd");
}];
[_thread start];
-(IBAction)resetTerminal: (id)sender {
[_emulator reset: NO];
}
-(IBAction)hardResetTerminal: (id)sender {
[_emulator reset: YES];
[_emulatorView reset];
}
#pragma mark -
#pragma mark NSWindowDelegate
- (void)windowDidLoad
{
NSColor *foregroundColor;
NSColor *backgroundColor;
Class klass;
id o;
NSWindow *window;
[super windowDidLoad];
window = [self window];
//[(CurveView *)[window contentView] setColor: [NSColor clearColor]];
//[window setContentView: _curveView];
// resize in 2.0 height increments to prevent jittering the scan lines.
//[window setResizeIncrements: NSMakeSize(1.0, 2.0)];
klass = [_parameters objectForKey: kClass];
if (!klass || ![klass conformsToProtocol: @protocol(Emulator)])
{
klass = Nil;
//klass = [VT52 class];
}
o = [_parameters objectForKey: kForegroundColor];
foregroundColor = o ? (NSColor *)o : [NSColor greenColor];
o = [_parameters objectForKey: kBackgroundColor];
backgroundColor = o ? (NSColor *)o : [NSColor blackColor];
[self willChangeValueForKey: @"emulator"];
_emulator = [klass new];
[self didChangeValueForKey: @"emulator"];
[window setBackgroundColor: backgroundColor];
[(EmulatorWindow *)window setTitleTextColor: foregroundColor];
window = [self window];
[_emulatorView setEmulator: _emulator];
[_emulatorView setForegroundColor: foregroundColor];
[_emulatorView setBackgroundColor: backgroundColor];
//[_emulatorView setScanLines: scanLines];
[_colorView setColor: backgroundColor];
o = [_parameters objectForKey: kContentFilters];
if (o)
{
[_colorView setWantsLayer: YES];
[_colorView setContentFilters: (NSArray *)o];
}
[self initPTY];
[self updateBackgroundColor];
[self updateForegroundColor];
[_colorView setWantsLayer: YES];
[_colorView setContentFilters: [self effectsFilter]];
if ([_emulator respondsToSelector: @selector(characterGenerator)]) {
id tmp = [_emulator characterGenerator];
[(EmulatorWindow *)window setTitleCharacterGenerator:tmp];
}
[self initPTY];
}
-(void)windowWillClose:(NSNotification *)notification
{
[[ChildMonitor monitor] removeController: self];
[self autorelease];
}
pid_t pid = std::atomic_exchange(&_pid, -1);
[_thread cancel];
-(void)windowDidBecomeKey:(NSNotification *)notification {
[_emulatorView popCursor];
}
if (pid > 0) {
kill(pid, 9);
-(void)windowDidResignKey:(NSNotification *)notification {
[_emulatorView pushCursor: Screen::CursorTypeBlock];
}
-(void)popoverWillClose:(NSNotification *)notification {
[_fg deactivate];
[_bg deactivate];
[[NSColorPanel sharedColorPanel] orderOut: self];
}
@end
@implementation TermWindowController (Config)
-(NSColor *)recalcBackgroundColor {
if (_effectsEnabled) {
return [_backgroundColor blendedColorWithFraction: _backlightValue ofColor: _foregroundColor];
}
return _backgroundColor;
}
-(IBAction)filterParameterChanged:(id)sender {
if (sender == _effectsButton) sender = nil;
if (sender == nil || sender == _fg) {
[self updateForegroundColor];
}
if (sender == nil || sender == _fg || sender == _bg || sender == _lightenSlider) {
[self updateBackgroundColor];
}
[self autorelease];
if (sender == nil || sender == _vignetteSlider || sender == _darkenSlider || sender == _bloomSlider) {
[_colorView setContentFilters: [self effectsFilter]];
}
#if 0
CIFilter *filter = [_contentFilters objectAtIndex: 0];
[filter setValue: @(_vignetteValue) forKey: @"inputIntensity"];
}
if (sender == _darkenSlider) {
CIFilter *filter = [_contentFilters objectAtIndex: 1];
[filter setValue: @(_scanlineValue) forKey: @"inputDarken"];
}
if (sender == _bloomSlider) {
CIFilter *filter = [_contentFilters objectAtIndex: 2];
[filter setValue: @(_bloomValue) forKey: @"inputIntensity"];
}
#endif
}
-(NSArray *)effectsFilter {
if (!_effectsEnabled) return @[];
CIFilter *filter;
NSMutableArray *filters = [NSMutableArray arrayWithCapacity: 5];
// 1. vignette effect
filter = [CIFilter filterWithName: @"CIVignette"];
[filter setDefaults];
[filter setValue: @(_vignetteValue) forKey: @"inputIntensity"];
[filter setValue: @(2.0) forKey: @"inputRadius"];
[filters addObject: filter];
// 2. add the scanlines
filter = [[ScanLineFilter new] autorelease];
[filter setValue: @(_scanlineValue) forKey: @"inputDarken"];
[filter setValue: @(0.0) forKey: @"inputLighten"];
[filters addObject: filter];
// 3. bloom it...
filter = [CIFilter filterWithName: @"CIBloom"];
[filter setDefaults];
[filter setValue: @2.0 forKey: @"inputRadius"];
[filter setValue: @(_bloomValue) forKey: @"inputIntensity"];
[filters addObject: filter];
#if 0
//4. blur it a bit...
filter = [CIFilter filterWithName: @"CIGaussianBlur"];
[filter setDefaults];
[filter setValue: @(_blurValue) forKey: @"inputRadius"];
[filters addObject: filter];
#endif
return filters;
}
#pragma mark - IBActions
-(IBAction)configure: (id)sender {
if (!_popover) {
NSNib *nib = [[NSNib alloc] initWithNibNamed: @"TermConfig" bundle: nil];
// n.b. - instantiateWithOwner (10.8+) does not +1 refcount top level objects.
[nib instantiateWithOwner: self topLevelObjects: nil];
[nib release];
}
if ([_popover isShown]) {
[_popover close];
} else {
[_popover showRelativeToRect: NSZeroRect ofView: _emulatorView preferredEdge: NSRectEdgeMaxX];
}
}
- (IBAction)foregroundColor:(id)sender {
[self updateForegroundColor];
}
- (IBAction)backgroundColor:(id)sender {
[self updateBackgroundColor];
}
- (IBAction)swapColors:(id)sender {
[self willChangeValueForKey: @"foregroundColor"];
[self willChangeValueForKey: @"backgroundColor"];
std::swap(_foregroundColor, _backgroundColor);
[self didChangeValueForKey: @"foregroundColor"];
[self didChangeValueForKey: @"backgroundColor"];
[self updateBackgroundColor];
[self updateForegroundColor];
if ([_fg isActive]) {
[_bg activate: YES];
} else if ([_bg isActive]) {
[_fg activate: YES];
}
}
-(void)updateForegroundColor {
NSColor *color = _foregroundColor;
NSWindow *window = [self window];
[(EmulatorWindow *)window setTitleTextColor: color];
[_emulatorView setForegroundColor: color];
}
-(void)updateBackgroundColor {
NSColor *color = [self recalcBackgroundColor];
NSWindow *window = [self window];
[window setBackgroundColor: color];
[_colorView setColor: color];
[_emulatorView setBackgroundColor: color];
}
@end

View File

@ -12,6 +12,8 @@
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
B609404C205ACD730077A69C /* VT05.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B683F711204AE32900470B99 /* VT05.mm.ragel */; };
B60942042082BCA200141159 /* VT100.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B60942022077F24300141159 /* VT100.mm.ragel */; };
B60EBD1211E8DEEF00C1974F /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B60EBD1111E8DEEF00C1974F /* QuartzCore.framework */; };
B60EBDE311E90FC300C1974F /* ScanLineFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = B60EBDE211E90FC300C1974F /* ScanLineFilter.m */; };
B60EBE2B11E918D500C1974F /* ScanLineFilter.cikernel in Resources */ = {isa = PBXBuildFile; fileRef = B60EBDE711E9143F00C1974F /* ScanLineFilter.cikernel */; };
@ -33,7 +35,6 @@
B61EF7D81482FB6D008C1891 /* titlebar-left.png in Resources */ = {isa = PBXBuildFile; fileRef = B61EF7D51482FB6D008C1891 /* titlebar-left.png */; };
B61EF7D91482FB6D008C1891 /* titlebar-right.png in Resources */ = {isa = PBXBuildFile; fileRef = B61EF7D61482FB6D008C1891 /* titlebar-right.png */; };
B638188214A179D60027D007 /* ColorView.m in Sources */ = {isa = PBXBuildFile; fileRef = B638188114A179D60027D007 /* ColorView.m */; };
B6407804201CE8BD00D3F2D1 /* GNOConsole.mm.ragel in Resources */ = {isa = PBXBuildFile; fileRef = B612F45B12DD5DF1005D1B77 /* GNOConsole.mm.ragel */; };
B6407805201CE93500D3F2D1 /* GNOConsole.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B612F45B12DD5DF1005D1B77 /* GNOConsole.mm.ragel */; };
B66412391480A070003BC8D3 /* EmulatorWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = B66412381480A070003BC8D3 /* EmulatorWindow.m */; };
B675F4A81E540394004B0D9C /* Screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B612F44D12DD5DAD005D1B77 /* Screen.cpp */; };
@ -44,9 +45,26 @@
B67B3CE512B6FA040033AE07 /* a2-charset-40.png in Resources */ = {isa = PBXBuildFile; fileRef = B67B3CE312B6FA040033AE07 /* a2-charset-40.png */; };
B67B3CE612B6FA040033AE07 /* a2-charset-80.png in Resources */ = {isa = PBXBuildFile; fileRef = B67B3CE412B6FA040033AE07 /* a2-charset-80.png */; };
B6801BD912EB549300B22E9E /* vt100-charset.png in Resources */ = {isa = PBXBuildFile; fileRef = B6801BD812EB549300B22E9E /* vt100-charset.png */; };
B683F7102049E7B000470B99 /* VT50.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B683F70F2049E7B000470B99 /* VT50.mm.ragel */; };
B68A37D221A9B9D9004CBDE4 /* a2-charset-80@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CD720349C8C00671774 /* a2-charset-80@2x.png */; };
B68A37D321A9C15C004CBDE4 /* a2-charset-40@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CDA20349C8E00671774 /* a2-charset-40@2x.png */; };
B68A37D421A9C161004CBDE4 /* vt52-charset@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CD920349C8D00671774 /* vt52-charset@2x.png */; };
B68A37D521A9C164004CBDE4 /* vt100-charset@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CD820349C8D00671774 /* vt100-charset@2x.png */; };
B68E632A12FF909D00EAFF5F /* ExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = B68E632912FF909C00EAFF5F /* ExampleView.m */; };
B69D0FBA202799B10073CCB7 /* TermConfig.xib in Resources */ = {isa = PBXBuildFile; fileRef = B69D0FB8202799B10073CCB7 /* TermConfig.xib */; };
B69E32A920221C9E0086D7B1 /* ChildMonitor.mm in Sources */ = {isa = PBXBuildFile; fileRef = B69E32A820221C9E0086D7B1 /* ChildMonitor.mm */; };
B6ACA2AD1E614E38000E774B /* VT52.mm in Sources */ = {isa = PBXBuildFile; fileRef = B612F46312DD5DF1005D1B77 /* VT52.mm */; };
B6ACA2AF1E635CEC000E774B /* vt52-charset.png in Resources */ = {isa = PBXBuildFile; fileRef = B6ACA2AE1E635CEC000E774B /* vt52-charset.png */; };
B6C0909021D292E20067F7A4 /* Apple3.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B6C0908D21D1BBE70067F7A4 /* Apple3.mm.ragel */; };
B6C21CCE2033382B00671774 /* TabClose_Busy.tiff in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CC82033382A00671774 /* TabClose_Busy.tiff */; };
B6C21CCF2033382B00671774 /* TabClose_Busy_Pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CC92033382A00671774 /* TabClose_Busy_Pressed.tiff */; };
B6C21CD02033382B00671774 /* TabClose.tiff in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CCA2033382A00671774 /* TabClose.tiff */; };
B6C21CD12033382B00671774 /* TabClose_Pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CCB2033382B00671774 /* TabClose_Pressed.tiff */; };
B6C21CD22033382B00671774 /* TabClose_Rollover.tiff in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CCC2033382B00671774 /* TabClose_Rollover.tiff */; };
B6C21CD32033382B00671774 /* TabClose_Busy_Rollover.tiff in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CCD2033382B00671774 /* TabClose_Busy_Rollover.tiff */; };
B6C21CD62033580200671774 /* RolloverButton.m in Sources */ = {isa = PBXBuildFile; fileRef = B6C21CD52033580200671774 /* RolloverButton.m */; };
B6C21CE1203510CC00671774 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CE0203510CC00671774 /* Images.xcassets */; };
B6C21CE52035262200671774 /* Defaults.plist in Resources */ = {isa = PBXBuildFile; fileRef = B6C21CE42035262200671774 /* Defaults.plist */; };
B6C704EF15CCC64100CC0401 /* titlebar-center@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C704EC15CCC64100CC0401 /* titlebar-center@2x.png */; };
B6C704F015CCC64100CC0401 /* titlebar-left@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C704ED15CCC64100CC0401 /* titlebar-left@2x.png */; };
B6C704F115CCC64100CC0401 /* titlebar-right@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C704EE15CCC64100CC0401 /* titlebar-right@2x.png */; };
@ -60,6 +78,8 @@
isa = PBXBuildRule;
compilerSpec = "com.apple.build-tasks.copy-strings-file";
fileType = sourcecode.glsl;
inputFiles = (
);
isEditable = 1;
outputFiles = (
);
@ -70,6 +90,8 @@
compilerSpec = com.apple.compilers.proxy.script;
filePatterns = "*.mm.ragel";
fileType = pattern.proxy;
inputFiles = (
);
isEditable = 1;
outputFiles = (
"$(DERIVED_SOURCES_DIR)/$(INPUT_FILE_BASE)",
@ -91,10 +113,8 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
256AC3D80F4B6AC300CF3369 /* TwoTermAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoTermAppDelegate.h; sourceTree = "<group>"; };
256AC3D90F4B6AC300CF3369 /* TwoTermAppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TwoTermAppDelegate.mm; sourceTree = "<group>"; };
256AC3F00F4B6AF500CF3369 /* TwoTerm_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoTerm_Prefix.pch; sourceTree = "<group>"; };
@ -103,6 +123,11 @@
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8D1107320486CEB800E47090 /* TwoTerm.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TwoTerm.app; sourceTree = BUILT_PRODUCTS_DIR; };
B60942022077F24300141159 /* VT100.mm.ragel */ = {isa = PBXFileReference; lastKnownFileType = text; path = VT100.mm.ragel; sourceTree = "<group>"; };
B60B98712022BAF100E688E3 /* appleIIgs.ti */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = appleIIgs.ti; sourceTree = "<group>"; };
B60B98732022BAF100E688E3 /* gno-console.ti */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "gno-console.ti"; sourceTree = "<group>"; };
B60B98742022BAF100E688E3 /* gsos-console.ti */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "gsos-console.ti"; sourceTree = "<group>"; };
B60B98762022BAF100E688E3 /* proterm-special.ti */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "proterm-special.ti"; sourceTree = "<group>"; };
B60EBD1111E8DEEF00C1974F /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
B60EBDE111E90FC300C1974F /* ScanLineFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScanLineFilter.h; sourceTree = "<group>"; };
B60EBDE211E90FC300C1974F /* ScanLineFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScanLineFilter.m; sourceTree = "<group>"; };
@ -141,10 +166,8 @@
B61D0D68125B8E06001C713B /* Defaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Defaults.m; sourceTree = "<group>"; };
B61EF7C31481561E008C1891 /* titlebar-corner.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "titlebar-corner.png"; sourceTree = "<group>"; };
B61EF7C41481561E008C1891 /* titlebar-middle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "titlebar-middle.png"; sourceTree = "<group>"; };
B61EF7C814815AF8008C1891 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/NewTerminal.xib; sourceTree = "<group>"; };
B61EF7CA14815E07008C1891 /* TitleBarView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TitleBarView.h; sourceTree = "<group>"; };
B61EF7CB14815E07008C1891 /* TitleBarView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TitleBarView.m; sourceTree = "<group>"; };
B61EF7CE148163E7008C1891 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/TitleBarView.xib; sourceTree = "<group>"; };
B61EF7D41482FB6D008C1891 /* titlebar-center.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "titlebar-center.png"; sourceTree = "<group>"; };
B61EF7D51482FB6D008C1891 /* titlebar-left.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "titlebar-left.png"; sourceTree = "<group>"; };
B61EF7D61482FB6D008C1891 /* titlebar-right.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "titlebar-right.png"; sourceTree = "<group>"; };
@ -154,17 +177,44 @@
B66412381480A070003BC8D3 /* EmulatorWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EmulatorWindow.m; sourceTree = "<group>"; };
B676063911DEAD3500D6B66C /* TermWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TermWindowController.h; sourceTree = "<group>"; };
B676063A11DEAD3500D6B66C /* TermWindowController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TermWindowController.mm; sourceTree = "<group>"; };
B676064D11DEBAE300D6B66C /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/TermWindow.xib; sourceTree = "<group>"; };
B67B3CE312B6FA040033AE07 /* a2-charset-40.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "a2-charset-40.png"; sourceTree = "<group>"; };
B67B3CE412B6FA040033AE07 /* a2-charset-80.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "a2-charset-80.png"; sourceTree = "<group>"; };
B6801BD812EB549300B22E9E /* vt100-charset.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "vt100-charset.png"; sourceTree = "<group>"; };
B683F70E2049E7B000470B99 /* VT50.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VT50.h; sourceTree = "<group>"; };
B683F70F2049E7B000470B99 /* VT50.mm.ragel */ = {isa = PBXFileReference; lastKnownFileType = text; path = VT50.mm.ragel; sourceTree = "<group>"; };
B683F711204AE32900470B99 /* VT05.mm.ragel */ = {isa = PBXFileReference; lastKnownFileType = text; path = VT05.mm.ragel; sourceTree = "<group>"; };
B6887810235CD76A00407374 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
B6887811235CD76A00407374 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/TermWindow.xib; sourceTree = "<group>"; };
B6887812235CD76A00407374 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/NewTerminal.xib; sourceTree = "<group>"; };
B6887813235CD76B00407374 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/TermConfig.xib; sourceTree = "<group>"; };
B6887814235CD76B00407374 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/TitleBarView.xib; sourceTree = "<group>"; };
B6887815235CD77600407374 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
B68A37D621A9D45A004CBDE4 /* TwoTerm.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = TwoTerm.entitlements; path = TwoTerm/TwoTerm.entitlements; sourceTree = "<group>"; };
B68E632812FF909C00EAFF5F /* ExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleView.h; sourceTree = "<group>"; };
B68E632912FF909C00EAFF5F /* ExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleView.m; sourceTree = "<group>"; };
B69E32A820221C9E0086D7B1 /* ChildMonitor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ChildMonitor.mm; sourceTree = "<group>"; };
B69E32AA20221CCA0086D7B1 /* ChildMonitor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ChildMonitor.h; sourceTree = "<group>"; };
B6ACA2AB1E5C8BEC000E774B /* GNOConsole.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GNOConsole.mm; sourceTree = "<group>"; };
B6ACA2AE1E635CEC000E774B /* vt52-charset.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "vt52-charset.png"; sourceTree = "<group>"; };
B6C0908D21D1BBE70067F7A4 /* Apple3.mm.ragel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Apple3.mm.ragel; sourceTree = "<group>"; };
B6C0908F21D1D2070067F7A4 /* Apple3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Apple3.h; sourceTree = "<group>"; };
B6C173901D31D2B80024E360 /* GSOSConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GSOSConsole.h; sourceTree = "<group>"; };
B6C173911D31D2B80024E360 /* GSOSConsole.mm.ragel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GSOSConsole.mm.ragel; sourceTree = "<group>"; };
B6C173941D35546A0024E360 /* algorithm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = algorithm.h; sourceTree = "<group>"; };
B6C21CC82033382A00671774 /* TabClose_Busy.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = TabClose_Busy.tiff; sourceTree = "<group>"; };
B6C21CC92033382A00671774 /* TabClose_Busy_Pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = TabClose_Busy_Pressed.tiff; sourceTree = "<group>"; };
B6C21CCA2033382A00671774 /* TabClose.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = TabClose.tiff; sourceTree = "<group>"; };
B6C21CCB2033382B00671774 /* TabClose_Pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = TabClose_Pressed.tiff; sourceTree = "<group>"; };
B6C21CCC2033382B00671774 /* TabClose_Rollover.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = TabClose_Rollover.tiff; sourceTree = "<group>"; };
B6C21CCD2033382B00671774 /* TabClose_Busy_Rollover.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = TabClose_Busy_Rollover.tiff; sourceTree = "<group>"; };
B6C21CD42033580200671774 /* RolloverButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RolloverButton.h; sourceTree = "<group>"; };
B6C21CD52033580200671774 /* RolloverButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RolloverButton.m; sourceTree = "<group>"; };
B6C21CD720349C8C00671774 /* a2-charset-80@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "a2-charset-80@2x.png"; sourceTree = "<group>"; };
B6C21CD820349C8D00671774 /* vt100-charset@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "vt100-charset@2x.png"; sourceTree = "<group>"; };
B6C21CD920349C8D00671774 /* vt52-charset@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "vt52-charset@2x.png"; sourceTree = "<group>"; };
B6C21CDA20349C8E00671774 /* a2-charset-40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "a2-charset-40@2x.png"; sourceTree = "<group>"; };
B6C21CE0203510CC00671774 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = TwoTerm/Images.xcassets; sourceTree = "<group>"; };
B6C21CE42035262200671774 /* Defaults.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Defaults.plist; sourceTree = "<group>"; };
B6C704EC15CCC64100CC0401 /* titlebar-center@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "titlebar-center@2x.png"; sourceTree = "<group>"; };
B6C704ED15CCC64100CC0401 /* titlebar-left@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "titlebar-left@2x.png"; sourceTree = "<group>"; };
B6C704EE15CCC64100CC0401 /* titlebar-right@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "titlebar-right@2x.png"; sourceTree = "<group>"; };
@ -201,6 +251,8 @@
B6EBE2B411E0EA9100EA0458 /* CharacterGenerator.mm */,
B60EBDE111E90FC300C1974F /* ScanLineFilter.h */,
B60EBDE211E90FC300C1974F /* ScanLineFilter.m */,
B69E32A820221C9E0086D7B1 /* ChildMonitor.mm */,
B69E32AA20221CCA0086D7B1 /* ChildMonitor.h */,
);
name = Classes;
sourceTree = "<group>";
@ -235,6 +287,7 @@
29B97314FDCFA39411CA2CEA /* 2Term */ = {
isa = PBXGroup;
children = (
B68A37D621A9D45A004CBDE4 /* TwoTerm.entitlements */,
B612F46B12DD5E02005D1B77 /* Views */,
B612F45512DD5DF1005D1B77 /* Emulators */,
B612F44612DD5DAD005D1B77 /* cpp */,
@ -261,13 +314,17 @@
29B97317FDCFA39411CA2CEA /* Resources */ = {
isa = PBXGroup;
children = (
B6C21CE0203510CC00671774 /* Images.xcassets */,
B60B98702022BAF100E688E3 /* a2-terminfo */,
B60EBDE711E9143F00C1974F /* ScanLineFilter.cikernel */,
B66979CE11E6BCAE002ED475 /* images */,
8D1107310486CEB800E47090 /* Info.plist */,
B6C21CE42035262200671774 /* Defaults.plist */,
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
1DDD58140DA1D0A300B32029 /* MainMenu.xib */,
B676065011DEBAE900D6B66C /* TermWindow.xib */,
B61EF7C714815AF8008C1891 /* NewTerminal.xib */,
B69D0FB8202799B10073CCB7 /* TermConfig.xib */,
B61EF7CD148163E7008C1891 /* TitleBarView.xib */,
);
name = Resources;
@ -282,13 +339,24 @@
name = Frameworks;
sourceTree = "<group>";
};
B60B98702022BAF100E688E3 /* a2-terminfo */ = {
isa = PBXGroup;
children = (
B60B98712022BAF100E688E3 /* appleIIgs.ti */,
B60B98732022BAF100E688E3 /* gno-console.ti */,
B60B98742022BAF100E688E3 /* gsos-console.ti */,
B60B98762022BAF100E688E3 /* proterm-special.ti */,
);
path = "a2-terminfo";
sourceTree = "<group>";
};
B612F44612DD5DAD005D1B77 /* cpp */ = {
isa = PBXGroup;
children = (
B612F44812DD5DAD005D1B77 /* iGeometry.h */,
B612F44712DD5DAD005D1B77 /* iGeometry.cpp */,
B6D5A0831E3996BD004FC1AC /* ring_buffer.h */,
B6C173941D35546A0024E360 /* algorithm.h */,
B612F44812DD5DAD005D1B77 /* iGeometry.h */,
B612F44912DD5DAD005D1B77 /* Lock.cpp */,
B612F44A12DD5DAD005D1B77 /* Lock.h */,
B612F44B12DD5DAD005D1B77 /* OutputChannel.cpp */,
@ -306,7 +374,9 @@
B612F45912DD5DF1005D1B77 /* EmulatorManager.mm */,
B612F45612DD5DF1005D1B77 /* Apple80.h */,
B612F45712DD5DF1005D1B77 /* Apple80.mm.ragel */,
B6C0908D21D1BBE70067F7A4 /* Apple3.mm.ragel */,
B612F45A12DD5DF1005D1B77 /* GNOConsole.h */,
B6C0908F21D1D2070067F7A4 /* Apple3.h */,
B612F45B12DD5DF1005D1B77 /* GNOConsole.mm.ragel */,
B6ACA2AB1E5C8BEC000E774B /* GNOConsole.mm */,
B6C173901D31D2B80024E360 /* GSOSConsole.h */,
@ -315,10 +385,14 @@
B612F45D12DD5DF1005D1B77 /* PTSE.mm.ragel */,
B612F45E12DD5DF1005D1B77 /* VT05.h */,
B612F45F12DD5DF1005D1B77 /* VT05.mm */,
B683F711204AE32900470B99 /* VT05.mm.ragel */,
B612F46012DD5DF1005D1B77 /* VT100.h */,
B612F46112DD5DF1005D1B77 /* VT100.mm */,
B612F46212DD5DF1005D1B77 /* VT52.h */,
B612F46312DD5DF1005D1B77 /* VT52.mm */,
B683F70E2049E7B000470B99 /* VT50.h */,
B683F70F2049E7B000470B99 /* VT50.mm.ragel */,
B60942022077F24300141159 /* VT100.mm.ragel */,
);
path = Emulators;
sourceTree = "<group>";
@ -342,6 +416,8 @@
B6ECFF261D2EEA2B00871A81 /* TextLabel.m */,
B638188014A179D60027D007 /* ColorView.h */,
B638188114A179D60027D007 /* ColorView.m */,
B6C21CD42033580200671774 /* RolloverButton.h */,
B6C21CD52033580200671774 /* RolloverButton.m */,
);
path = Views;
sourceTree = "<group>";
@ -349,6 +425,12 @@
B66979CE11E6BCAE002ED475 /* images */ = {
isa = PBXGroup;
children = (
B6C21CC92033382A00671774 /* TabClose_Busy_Pressed.tiff */,
B6C21CCD2033382B00671774 /* TabClose_Busy_Rollover.tiff */,
B6C21CC82033382A00671774 /* TabClose_Busy.tiff */,
B6C21CCB2033382B00671774 /* TabClose_Pressed.tiff */,
B6C21CCC2033382B00671774 /* TabClose_Rollover.tiff */,
B6C21CCA2033382A00671774 /* TabClose.tiff */,
B61EF7D41482FB6D008C1891 /* titlebar-center.png */,
B61EF7D51482FB6D008C1891 /* titlebar-left.png */,
B61EF7D61482FB6D008C1891 /* titlebar-right.png */,
@ -361,6 +443,10 @@
B6ACA2AE1E635CEC000E774B /* vt52-charset.png */,
B67B3CE312B6FA040033AE07 /* a2-charset-40.png */,
B67B3CE412B6FA040033AE07 /* a2-charset-80.png */,
B6C21CDA20349C8E00671774 /* a2-charset-40@2x.png */,
B6C21CD720349C8C00671774 /* a2-charset-80@2x.png */,
B6C21CD920349C8D00671774 /* vt52-charset@2x.png */,
B6C21CD820349C8D00671774 /* vt100-charset@2x.png */,
);
path = images;
sourceTree = "<group>";
@ -376,6 +462,7 @@
8D11072C0486CEB800E47090 /* Sources */,
8D11072E0486CEB800E47090 /* Frameworks */,
B61D0D57125B728D001C713B /* CopyFiles */,
B60B98802022BF5900E688E3 /* ShellScript */,
);
buildRules = (
B6C173931D32A8840024E360 /* PBXBuildRule */,
@ -395,15 +482,25 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
LastUpgradeCheck = 1110;
TargetAttributes = {
8D1107260486CEB800E47090 = {
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.HardenedRuntime = {
enabled = 1;
};
};
};
};
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "TwoTerm" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 1;
knownRegions = (
en,
English,
Base,
);
mainGroup = 29B97314FDCFA39411CA2CEA /* 2Term */;
projectDirPath = "";
@ -419,39 +516,73 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B6C21CE52035262200671774 /* Defaults.plist in Resources */,
B60EBE2B11E918D500C1974F /* ScanLineFilter.cikernel in Resources */,
B6C21CD12033382B00671774 /* TabClose_Pressed.tiff in Resources */,
B6C21CCF2033382B00671774 /* TabClose_Busy_Pressed.tiff in Resources */,
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
B69D0FBA202799B10073CCB7 /* TermConfig.xib in Resources */,
B68A37D421A9C161004CBDE4 /* vt52-charset@2x.png in Resources */,
1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */,
B676065111DEBAE900D6B66C /* TermWindow.xib in Resources */,
B67B3CE512B6FA040033AE07 /* a2-charset-40.png in Resources */,
B6C21CD02033382B00671774 /* TabClose.tiff in Resources */,
B67B3CE612B6FA040033AE07 /* a2-charset-80.png in Resources */,
B6407804201CE8BD00D3F2D1 /* GNOConsole.mm.ragel in Resources */,
B6801BD912EB549300B22E9E /* vt100-charset.png in Resources */,
B68A37D321A9C15C004CBDE4 /* a2-charset-40@2x.png in Resources */,
B6C21CCE2033382B00671774 /* TabClose_Busy.tiff in Resources */,
B6C21CD32033382B00671774 /* TabClose_Busy_Rollover.tiff in Resources */,
B61EF7C51481561E008C1891 /* titlebar-corner.png in Resources */,
B61EF7C61481561E008C1891 /* titlebar-middle.png in Resources */,
B68A37D521A9C164004CBDE4 /* vt100-charset@2x.png in Resources */,
B68A37D221A9B9D9004CBDE4 /* a2-charset-80@2x.png in Resources */,
B61EF7C914815AF8008C1891 /* NewTerminal.xib in Resources */,
B61EF7CF148163E7008C1891 /* TitleBarView.xib in Resources */,
B61EF7D71482FB6D008C1891 /* titlebar-center.png in Resources */,
B6C21CE1203510CC00671774 /* Images.xcassets in Resources */,
B61EF7D81482FB6D008C1891 /* titlebar-left.png in Resources */,
B61EF7D91482FB6D008C1891 /* titlebar-right.png in Resources */,
B6C704EF15CCC64100CC0401 /* titlebar-center@2x.png in Resources */,
B6C704F015CCC64100CC0401 /* titlebar-left@2x.png in Resources */,
B6C704F115CCC64100CC0401 /* titlebar-right@2x.png in Resources */,
B6C21CD22033382B00671774 /* TabClose_Rollover.tiff in Resources */,
B6ACA2AF1E635CEC000E774B /* vt52-charset.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
B60B98802022BF5900E688E3 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "for x in \"$PROJECT_DIR/a2-terminfo/\"*.ti ; do\ntic -N -s -o \"$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/terminfo\" \"$x\"\ndone";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8D11072C0486CEB800E47090 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B675F4A91E561D20004B0D9C /* Apple80.mm.ragel in Sources */,
B6C0909021D292E20067F7A4 /* Apple3.mm.ragel in Sources */,
B675F4AC1E56A7F2004B0D9C /* GSOSConsole.mm.ragel in Sources */,
B6D1CD071E577E7D00C4A6BC /* PTSE.mm.ragel in Sources */,
B683F7102049E7B000470B99 /* VT50.mm.ragel in Sources */,
B6407805201CE93500D3F2D1 /* GNOConsole.mm.ragel in Sources */,
B609404C205ACD730077A69C /* VT05.mm.ragel in Sources */,
B60942042082BCA200141159 /* VT100.mm.ragel in Sources */,
B6C21CD62033580200671774 /* RolloverButton.m in Sources */,
B69E32A920221C9E0086D7B1 /* ChildMonitor.mm in Sources */,
8D11072D0486CEB800E47090 /* main.m in Sources */,
256AC3DA0F4B6AC300CF3369 /* TwoTermAppDelegate.mm in Sources */,
B676063B11DEAD3500D6B66C /* TermWindowController.mm in Sources */,
@ -482,7 +613,7 @@
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
089C165DFE840E0CC02AAC07 /* English */,
B6887815235CD77600407374 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
@ -490,7 +621,7 @@
1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
1DDD58150DA1D0A300B32029 /* English */,
B6887810235CD76A00407374 /* Base */,
);
name = MainMenu.xib;
sourceTree = "<group>";
@ -498,7 +629,7 @@
B61EF7C714815AF8008C1891 /* NewTerminal.xib */ = {
isa = PBXVariantGroup;
children = (
B61EF7C814815AF8008C1891 /* English */,
B6887812235CD76A00407374 /* Base */,
);
name = NewTerminal.xib;
sourceTree = "<group>";
@ -506,7 +637,7 @@
B61EF7CD148163E7008C1891 /* TitleBarView.xib */ = {
isa = PBXVariantGroup;
children = (
B61EF7CE148163E7008C1891 /* English */,
B6887814235CD76B00407374 /* Base */,
);
name = TitleBarView.xib;
sourceTree = "<group>";
@ -514,11 +645,19 @@
B676065011DEBAE900D6B66C /* TermWindow.xib */ = {
isa = PBXVariantGroup;
children = (
B676064D11DEBAE300D6B66C /* English */,
B6887811235CD76A00407374 /* Base */,
);
name = TermWindow.xib;
sourceTree = "<group>";
};
B69D0FB8202799B10073CCB7 /* TermConfig.xib */ = {
isa = PBXVariantGroup;
children = (
B6887813235CD76B00407374 /* Base */,
);
name = TermConfig.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
@ -526,8 +665,14 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_OBJC_WEAK = YES;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GCC_DYNAMIC_NO_PIC = NO;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
@ -537,6 +682,7 @@
INSTALL_PATH = "$(HOME)/Applications";
PRODUCT_BUNDLE_IDENTIFIER = "com.ksherlock.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = TwoTerm;
PROVISIONING_PROFILE_SPECIFIER = "";
};
name = Debug;
};
@ -544,8 +690,13 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_OBJC_WEAK = YES;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = TwoTerm_Prefix.pch;
@ -566,11 +717,13 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
@ -605,11 +758,13 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;

View File

@ -0,0 +1,66 @@
{
"images" : [
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "icon-32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "icon-32@2x.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon-128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon-128@2x.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "icon-256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "icon-256@2x.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "icon-512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "icon-512@2x.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>

View File

@ -13,7 +13,7 @@
#import "Defaults.h"
//#import "VT52.h"
#import "GNOConsole.h"
#import "ChildMonitor.h"
#import "ScanLineFilter.h"
@implementation TwoTermAppDelegate
@ -27,9 +27,7 @@
TermWindowController *controller;
NSMutableArray *filters;
NSDictionary *parameters;
CIFilter *filter;
#if 0
struct sigaction sa = {};
@ -42,7 +40,7 @@
[nc addObserver: self selector: @selector(newTerminal:) name: kNotificationNewTerminal object: nil];
#if 0
filters = [NSMutableArray arrayWithCapacity: 5];
@ -76,12 +74,12 @@
[filter setValue: @2.0 forKey: @"inputRadius"];
[filter setValue: @(0.75) forKey: @"inputIntensity"];
#endif
parameters = @{
kClass: [GNOConsole class],
kContentFilters: filters,
//kContentFilters: filters,
kForegroundColor: [NSColor colorWithRed: 0.0 green: 1.0 blue: 0.6 alpha: 1.0],
kBackgroundColor: [NSColor colorWithRed: 0.0 green: .25 blue: .15 alpha: 1.0]
};
@ -92,6 +90,10 @@
// this leak is ok.
}
-(void)applicationWillTerminate:(NSNotification *)notification {
[[ChildMonitor monitor] removeAll];
}
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver: self];

View File

@ -73,13 +73,14 @@ private:
unsigned _cursorType;
NSImage *_cursors[4];
NSImage *_cursors[5];
#ifdef __cplusplus
ring_buffer<1024> _debug_buffer;
ViewScreen _screen;
#endif
std::vector<unsigned> _cursorStack;
}
@property (nonatomic, assign) BOOL scanLines;
@ -110,6 +111,8 @@ private:
-(void)processData: (uint8_t *)data size: (size_t)size;
-(void)childFinished: (int)status;
-(void)childBegan;
-(void)reset;
@end
@ -121,5 +124,7 @@ private:
-(void)cursorTimer: (NSTimer *)timer;
-(void)startCursorTimer;
-(void)pushCursor: (unsigned)type;
-(void)popCursor;
@end

View File

@ -58,6 +58,7 @@
[_cursorTimer release];
_cursorTimer = nil;
_cursorOn = YES;
iRect r(_screen.cursor(), iSize(1,1));
[self invalidateIRect: r];
}
@ -95,30 +96,24 @@
{
return _cursorType;
}
#if 0
dispatch_async(dispatch_get_main_queue(), ^(){
if (_cursorType == cursorType) return;
-(void)pushCursor:(unsigned)type {
if (_fd < 0) return;
unsigned char c;
switch (cursorType) {
default:
case Screen::CursorTypeUnderscore: c = '_'; break;
case Screen::CursorTypePipe: c = '|'; break;
case Screen::CursorTypeBlock: c = 0x80; break;
}
[_cursorImg release];
_cursorType = cursorType;
_cursorImg = [[_charGen imageForCharacter: c] retain];
iRect r(_screen.cursor(), iSize(1,1));
[self invalidateIRect: r];
});
#endif
_cursorStack.push_back(_cursorType);
[self setCursorType: type];
[self stopCursorTimer];
}
-(void)popCursor {
if (_fd < 0) return;
if (!_cursorStack.empty()) {
[self setCursorType: _cursorStack.back()];
_cursorStack.pop_back();
if (_cursorStack.empty()) [self startCursorTimer];
}
}
@end
@ -148,19 +143,39 @@ dispatch_async(dispatch_get_main_queue(), ^(){
_screen.setFD(fd);
}
-(void)setCharacterGenerator: (CharacterGenerator *)generator {
if (generator != _charGen) {
[_charGen release];
_charGen = [generator retain];
NSSize size = [_charGen characterSize];
_charWidth = size.width;
_charHeight = size.height;
}
}
-(void)setEmulator:(NSObject<Emulator> *)emulator {
if (_emulator == emulator) return;
[_emulator release];
_emulator = [emulator retain];
if ([emulator respondsToSelector: @selector(characterGenerator)]) {
id cg = [emulator characterGenerator];
if (cg) [self setCharacterGenerator: cg];
}
}
#pragma mark -
-(void)awakeFromNib
{
NSSize size;
_charWidth = 7;
_charHeight = 16;
_paddingLeft = 8;
_paddingTop = 8;
_paddingBottom = 8;
_fd = -1;
//_foregroundColor = [[NSColor greenColor] retain];
//_backgroundColor = [[NSColor blackColor] retain];
@ -173,7 +188,7 @@ dispatch_async(dispatch_get_main_queue(), ^(){
_screen.setFD(_fd);
_screen.setView(self);
_charGen = [[CharacterGenerator generator] retain];
[self setCharacterGenerator: [CharacterGenerator generatorForCharacterSet: CGApple80]];
_cursorType = Screen::CursorTypeUnderscore;
@ -181,12 +196,9 @@ dispatch_async(dispatch_get_main_queue(), ^(){
_cursors[Screen::CursorTypeUnderscore] = [[_charGen imageForCharacter: '_'] retain];
_cursors[Screen::CursorTypePipe] = [[_charGen imageForCharacter: '|'] retain];
_cursors[Screen::CursorTypeBlock] = [[_charGen imageForCharacter: 0x80] retain];
_cursors[Screen::CursorTypeCrossHatch] = [[_charGen imageForCharacter: 0x7f] retain];
size = [_charGen characterSize];
_charWidth = size.width;
_charHeight = size.height;
// enable drag+drop for files/urls.
@ -214,49 +226,6 @@ dispatch_async(dispatch_get_main_queue(), ^(){
[self setNeedsDisplay: YES];
}
-(void)setScanLines:(BOOL)scanLines
{
if (_scanLines == scanLines) return;
_scanLines = scanLines;
if (_scanLines)
{
NSMutableArray *filters;
CIFilter *filter;
[self setWantsLayer: YES];
filters = [NSMutableArray arrayWithCapacity: 3];
//add the scanlines
filter = [[ScanLineFilter new] autorelease];
[filter setValue: [NSNumber numberWithFloat: 1.0] forKey: @"inputDarken"];
[filter setValue: [NSNumber numberWithFloat: 0.025] forKey: @"inputLighten"];
[filters addObject: filter];
//blur it a bit...
filter = [CIFilter filterWithName: @"CIGaussianBlur"];
[filter setDefaults];
[filter setValue: [NSNumber numberWithFloat: 0.33] forKey: @"inputRadius"];
[filters addObject: filter];
[self setContentFilters: filters];
}
else
{
[self setContentFilters: @[]];
}
}
-(BOOL)isFlipped
{
return YES;
@ -273,11 +242,6 @@ dispatch_async(dispatch_get_main_queue(), ^(){
[self startCursorTimer];
/*
[[self window] display];
[[self window] setHasShadow: NO];
[[self window] setHasShadow: YES];
*/
}
-(void)viewDidMoveToSuperview
@ -285,6 +249,10 @@ dispatch_async(dispatch_get_main_queue(), ^(){
[self becomeFirstResponder];
}
-(BOOL)canBecomeKeyView {
return YES;
}
-(BOOL)acceptsFirstResponder
{
return YES;
@ -375,9 +343,9 @@ dispatch_async(dispatch_get_main_queue(), ^(){
{
// mouse text actually requires mouse text and inverse to be on.
if (flag & Screen::FlagMouseText)
if ((flag & Screen::FlagMouseText) && c >= '@' && c <= '_')
{
if (c >= '@' && c <= '_') c |= 0x80;
c |= 0x80;
}
else
{
@ -467,8 +435,6 @@ dispatch_async(dispatch_get_main_queue(), ^(){
-(void)dealloc
{
close(_fd);
[_foregroundColor release];
[_backgroundColor release];
@ -531,11 +497,12 @@ dispatch_async(dispatch_get_main_queue(), ^(){
//NSLog(@"[process complete]");
_fd = -1;
dispatch_async(dispatch_get_main_queue(), ^(){
iRect updateRect;
[self setCursorType: Screen::CursorTypeNone];
[self setCursorType: Screen::CursorTypeCrossHatch];
[self stopCursorTimer];
//_screen.setCursorType(Screen::CursorTypeNone);
@ -802,7 +769,7 @@ dispatch_async(dispatch_get_main_queue(), ^(){
SEL cmd = [anItem action];
if (cmd == @selector(paste:)) {
return _fd >= 1;
return _fd >= 0;
}
if (cmd == @selector(copy:)) return NO;
if (cmd == @selector(copyDebugData:)) return YES;
@ -921,7 +888,12 @@ dispatch_async(dispatch_get_main_queue(), ^(){
}
-(void)reset {
_screen.eraseScreen();
_screen.setCursor(iPoint(0,0));
_cursorOn = YES;
[self setNeedsDisplay: YES];
}
@end

View File

@ -8,6 +8,7 @@
#import <AppKit/AppKit.h>
@class TextLabel;
@class CharacterGenerator;
@interface EmulatorWindow : NSWindow
{
@ -16,5 +17,5 @@
@property (assign) IBOutlet TextLabel *textLabel;
-(void)setTitleTextColor: (NSColor *)color;
-(void)setTitleCharacterGenerator: (CharacterGenerator *)characterGenerator;
@end

View File

@ -85,6 +85,11 @@
[super setBackgroundColor: color];
}
-(void)setTitleCharacterGenerator: (CharacterGenerator *)characterGenerator {
[_textLabel setCharacterGenerator: characterGenerator];
}
-(void)awakeFromNib
{

16
Views/RolloverButton.h Normal file
View File

@ -0,0 +1,16 @@
//
// RolloverButton.h
// TwoTerm
//
// Created by Kelvin Sherlock on 2/13/2018.
//
#import <Cocoa/Cocoa.h>
@interface RolloverButton : NSButton {
NSImage *_image;
NSImage *_rolloverImage;
NSTrackingArea *_trackingArea;
BOOL _rollOver;
}
@end

98
Views/RolloverButton.m Normal file
View File

@ -0,0 +1,98 @@
//
// RolloverButton.m
// TwoTerm
//
// Created by Kelvin Sherlock on 2/13/2018.
//
#import "RolloverButton.h"
@implementation RolloverButton
#if 0
- (void)createTrackingArea
{
NSTrackingAreaOptions focusTrackingAreaOptions = 0;
focusTrackingAreaOptions |= NSTrackingActiveInActiveApp;
focusTrackingAreaOptions |= NSTrackingMouseEnteredAndExited;
//focusTrackingAreaOptions |= NSTrackingAssumeInside;
focusTrackingAreaOptions |= NSTrackingInVisibleRect;
NSTrackingArea *focusTrackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect
options:focusTrackingAreaOptions
owner:self userInfo:nil];
[self addTrackingArea:focusTrackingArea];
[focusTrackingArea release];
}
#endif
- (void) updateTrackingAreas {
[super updateTrackingAreas];
if (_trackingArea) {
[self removeTrackingArea: _trackingArea];
[_trackingArea release];
}
NSTrackingAreaOptions options = 0;
options |= NSTrackingActiveInActiveApp;
options |= NSTrackingMouseEnteredAndExited;
//options |= NSTrackingAssumeInside;
options |= NSTrackingInVisibleRect;
_trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect
options:options
owner:self
userInfo:nil];
[self addTrackingArea: _trackingArea];
}
-(void)setImage:(NSImage *)image {
if (_image != image) {
[_image release];
_image = [image retain];
}
if (!_rollOver) [super setImage: image];
}
-(void)setRolloverImage: (NSImage *)image {
if (_rolloverImage != image) {
[_rolloverImage release];
_rolloverImage = [image retain];
}
if (_rollOver) [super setImage: image];
}
-(void)awakeFromNib {
[super awakeFromNib];
//[self createTrackingArea];
[self setImage: [NSImage imageNamed: @"TabClose"]];
[self setRolloverImage: [NSImage imageNamed: @"TabClose_Rollover"]];
[[self cell] setHighlightsBy: NSContentsCellMask];
}
-(void)dealloc {
[_image release];
[_rolloverImage release];
[super dealloc];
}
-(void)mouseExited:(NSEvent *)event {
[[self cell] setImage: _image];
_rollOver = NO;
[super mouseExited: event];
}
-(void) mouseEntered:(NSEvent *)event {
[[self cell] setImage: _rolloverImage];
_rollOver = YES;
[super mouseEntered: event];
}
@end

View File

@ -8,12 +8,15 @@
#import <Cocoa/Cocoa.h>
@class CharacterGenerator;
@interface TextLabel : NSView
{
NSString *_text;
NSColor *_color;
CharacterGenerator *_generator;
}
@property (nonatomic, retain) NSString *text;
@property (nonatomic, retain) NSColor *color;
@property (nonatomic, retain) CharacterGenerator *characterGenerator;
@end

View File

@ -14,6 +14,7 @@
@synthesize text = _text;
@synthesize color = _color;
@synthesize characterGenerator = _characterGenerator;
-(void) setText:(NSString *)text {
if (_text == text) return;
@ -29,6 +30,14 @@
[self setNeedsDisplay: YES];
}
-(void) setCharacterGenerator:(CharacterGenerator *)characterGenerator {
if (_characterGenerator == characterGenerator) return;
[_characterGenerator release];
_characterGenerator = [characterGenerator retain];
[self setNeedsDisplay: YES];
}
/*
-(BOOL)isFlipped {
return YES;
@ -42,6 +51,7 @@
[_text release];
[_color release];
[_characterGenerator release];
[super dealloc];
}
@ -55,9 +65,7 @@
if (!length) return;
if (!_color) return;
CharacterGenerator *gen = [CharacterGenerator generator];
NSSize sz = [gen characterSize];
NSSize sz = [_characterGenerator characterSize];
NSRect frame = [self frame];
@ -75,7 +83,7 @@
for (unsigned i = 0; i < length; ++i) {
unichar c = [_text characterAtIndex: i];
[gen drawCharacter: c atPoint: point];
[_characterGenerator drawCharacter: c atPoint: point];
point.x += sz.width;
if (point.x > NSWidth(frame)) break;
}
@ -89,6 +97,7 @@
if (!_text) _text = [@"Testing!" retain];
if (!_color) _color = [[NSColor greenColor] retain];
if (!_characterGenerator) _characterGenerator = [[CharacterGenerator generatorForCharacterSet: CGApple80] retain];
}

1
a2-terminfo Submodule

@ -0,0 +1 @@
Subproject commit c7b95dda17a1239b303d01eeca8c8f9fba3d2131

View File

@ -69,7 +69,8 @@ public:
CursorTypeNone,
CursorTypeUnderscore,
CursorTypePipe,
CursorTypeBlock
CursorTypeBlock,
CursorTypeCrossHatch,
};
Screen(unsigned height = 24, unsigned width = 80);

BIN
images/TabClose.tiff Normal file

Binary file not shown.

100
images/TabCloseButton.pdf Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

BIN
images/TabClose_Busy.tiff Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
images/TabNewButton.tiff Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
images/a2-charset-40@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
images/a2-charset-80@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
images/vt100-charset@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
images/vt52-charset@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB